diff options
author | Chocobozzz <florian.bigard@gmail.com> | 2016-11-11 11:52:24 +0100 |
---|---|---|
committer | Chocobozzz <florian.bigard@gmail.com> | 2016-11-16 20:29:26 +0100 |
commit | 6a94a109b4b89a97fe7bfeded3125fb7aad2ac3b (patch) | |
tree | 22397531c03da92be50e28703764405002acb926 | |
parent | 830bcd0f82c16b8b5f1259150a6d541a210693eb (diff) | |
download | PeerTube-6a94a109b4b89a97fe7bfeded3125fb7aad2ac3b.tar.gz PeerTube-6a94a109b4b89a97fe7bfeded3125fb7aad2ac3b.tar.zst PeerTube-6a94a109b4b89a97fe7bfeded3125fb7aad2ac3b.zip |
Server: add video preview
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | config/default.yaml | 1 | ||||
-rw-r--r-- | server.js | 7 | ||||
-rw-r--r-- | server/initializers/checker.js | 2 | ||||
-rw-r--r-- | server/initializers/constants.js | 4 | ||||
-rw-r--r-- | 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 @@ | |||
8 | /uploads/ | 8 | /uploads/ |
9 | /videos/ | 9 | /videos/ |
10 | /thumbnails/ | 10 | /thumbnails/ |
11 | /previews/ | ||
11 | /certs/ | 12 | /certs/ |
12 | /logs/ | 13 | /logs/ |
13 | /torrents/ | 14 | /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: | |||
16 | certs: 'certs/' | 16 | certs: 'certs/' |
17 | videos: 'videos/' | 17 | videos: 'videos/' |
18 | logs: 'logs/' | 18 | logs: 'logs/' |
19 | previews: 'previews/' | ||
19 | thumbnails: 'thumbnails/' | 20 | thumbnails: 'thumbnails/' |
20 | torrents: 'torrents/' | 21 | torrents: 'torrents/' |
@@ -71,7 +71,8 @@ const apiRoute = '/api/' + constants.API_VERSION | |||
71 | app.use(apiRoute, routes.api) | 71 | app.use(apiRoute, routes.api) |
72 | app.use('/', routes.client) | 72 | app.use('/', routes.client) |
73 | 73 | ||
74 | // Static files | 74 | // Static client files |
75 | // TODO: move in client | ||
75 | app.use('/client', express.static(path.join(__dirname, '/client/dist'), { maxAge: constants.STATIC_MAX_AGE })) | 76 | app.use('/client', express.static(path.join(__dirname, '/client/dist'), { maxAge: constants.STATIC_MAX_AGE })) |
76 | // 404 for static files not found | 77 | // 404 for static files not found |
77 | app.use('/client/*', function (req, res, next) { | 78 | app.use('/client/*', function (req, res, next) { |
@@ -89,6 +90,10 @@ app.use(constants.STATIC_PATHS.WEBSEED, cors(), express.static(videosPhysicalPat | |||
89 | const thumbnailsPhysicalPath = constants.CONFIG.STORAGE.THUMBNAILS_DIR | 90 | const thumbnailsPhysicalPath = constants.CONFIG.STORAGE.THUMBNAILS_DIR |
90 | app.use(constants.STATIC_PATHS.THUMBNAILS, express.static(thumbnailsPhysicalPath, { maxAge: constants.STATIC_MAX_AGE })) | 91 | app.use(constants.STATIC_PATHS.THUMBNAILS, express.static(thumbnailsPhysicalPath, { maxAge: constants.STATIC_MAX_AGE })) |
91 | 92 | ||
93 | // Video previews path for express | ||
94 | const previewsPhysicalPath = constants.CONFIG.STORAGE.PREVIEWS_DIR | ||
95 | app.use(constants.STATIC_PATHS.PREVIEWS, express.static(previewsPhysicalPath, { maxAge: constants.STATIC_MAX_AGE })) | ||
96 | |||
92 | // Always serve index client page | 97 | // Always serve index client page |
93 | app.use('/*', function (req, res, next) { | 98 | app.use('/*', function (req, res, next) { |
94 | res.sendFile(path.join(__dirname, './client/dist/index.html')) | 99 | 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 () { | |||
30 | const required = [ 'listen.port', | 30 | const required = [ 'listen.port', |
31 | 'webserver.https', 'webserver.hostname', 'webserver.port', | 31 | 'webserver.https', 'webserver.hostname', 'webserver.port', |
32 | 'database.hostname', 'database.port', 'database.suffix', | 32 | 'database.hostname', 'database.port', 'database.suffix', |
33 | 'storage.certs', 'storage.videos', 'storage.logs', 'storage.thumbnails' | 33 | 'storage.certs', 'storage.videos', 'storage.logs', 'storage.thumbnails', 'storage.previews' |
34 | ] | 34 | ] |
35 | const miss = [] | 35 | const miss = [] |
36 | 36 | ||
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 = { | |||
44 | LOG_DIR: path.join(__dirname, '..', '..', config.get('storage.logs')), | 44 | LOG_DIR: path.join(__dirname, '..', '..', config.get('storage.logs')), |
45 | VIDEOS_DIR: path.join(__dirname, '..', '..', config.get('storage.videos')), | 45 | VIDEOS_DIR: path.join(__dirname, '..', '..', config.get('storage.videos')), |
46 | THUMBNAILS_DIR: path.join(__dirname, '..', '..', config.get('storage.thumbnails')), | 46 | THUMBNAILS_DIR: path.join(__dirname, '..', '..', config.get('storage.thumbnails')), |
47 | PREVIEWS_DIR: path.join(__dirname, '..', '..', config.get('storage.previews')), | ||
47 | TORRENTS_DIR: path.join(__dirname, '..', '..', config.get('storage.torrents')) | 48 | TORRENTS_DIR: path.join(__dirname, '..', '..', config.get('storage.torrents')) |
48 | }, | 49 | }, |
49 | WEBSERVER: { | 50 | WEBSERVER: { |
@@ -135,6 +136,7 @@ const BCRYPT_SALT_SIZE = 10 | |||
135 | 136 | ||
136 | // Express static paths (router) | 137 | // Express static paths (router) |
137 | const STATIC_PATHS = { | 138 | const STATIC_PATHS = { |
139 | PREVIEWS: '/static/previews', | ||
138 | THUMBNAILS: '/static/thumbnails', | 140 | THUMBNAILS: '/static/thumbnails', |
139 | TORRENTS: '/static/torrents/', | 141 | TORRENTS: '/static/torrents/', |
140 | WEBSEED: '/static/webseed/' | 142 | WEBSEED: '/static/webseed/' |
@@ -145,6 +147,7 @@ let STATIC_MAX_AGE = '30d' | |||
145 | 147 | ||
146 | // Videos thumbnail size | 148 | // Videos thumbnail size |
147 | const THUMBNAILS_SIZE = '200x110' | 149 | const THUMBNAILS_SIZE = '200x110' |
150 | const PREVIEWS_SIZE = '640x480' | ||
148 | 151 | ||
149 | const USER_ROLES = { | 152 | const USER_ROLES = { |
150 | ADMIN: 'admin', | 153 | ADMIN: 'admin', |
@@ -179,6 +182,7 @@ module.exports = { | |||
179 | REQUESTS_INTERVAL, | 182 | REQUESTS_INTERVAL, |
180 | REQUESTS_LIMIT, | 183 | REQUESTS_LIMIT, |
181 | RETRY_REQUESTS, | 184 | RETRY_REQUESTS, |
185 | PREVIEWS_SIZE, | ||
182 | SEARCHABLE_COLUMNS, | 186 | SEARCHABLE_COLUMNS, |
183 | SORTABLE_COLUMNS, | 187 | SORTABLE_COLUMNS, |
184 | STATIC_MAX_AGE, | 188 | 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) { | |||
82 | }, | 82 | }, |
83 | function (callback) { | 83 | function (callback) { |
84 | removeTorrent(video, callback) | 84 | removeTorrent(video, callback) |
85 | }, | ||
86 | function (callback) { | ||
87 | removePreview(video, callback) | ||
85 | } | 88 | } |
86 | ) | 89 | ) |
87 | } | 90 | } |
@@ -125,6 +128,9 @@ VideoSchema.pre('save', function (next) { | |||
125 | }, | 128 | }, |
126 | function (callback) { | 129 | function (callback) { |
127 | createThumbnail(videoPath, callback) | 130 | createThumbnail(videoPath, callback) |
131 | }, | ||
132 | function (callback) { | ||
133 | createPreview(videoPath, callback) | ||
128 | } | 134 | } |
129 | ) | 135 | ) |
130 | 136 | ||
@@ -261,11 +267,30 @@ function removeFile (video, callback) { | |||
261 | fs.unlink(constants.CONFIG.STORAGE.VIDEOS_DIR + video.filename, callback) | 267 | fs.unlink(constants.CONFIG.STORAGE.VIDEOS_DIR + video.filename, callback) |
262 | } | 268 | } |
263 | 269 | ||
264 | // Maybe the torrent is not seeded, but we catch the error to don't stop the removing process | ||
265 | function removeTorrent (video, callback) { | 270 | function removeTorrent (video, callback) { |
266 | fs.unlink(constants.CONFIG.STORAGE.TORRENTS_DIR + video.filename + '.torrent', callback) | 271 | fs.unlink(constants.CONFIG.STORAGE.TORRENTS_DIR + video.filename + '.torrent', callback) |
267 | } | 272 | } |
268 | 273 | ||
274 | function removePreview (video, callback) { | ||
275 | // Same name than video thumnail | ||
276 | // TODO: refractoring | ||
277 | fs.unlink(constants.CONFIG.STORAGE.PREVIEWS_DIR + video.thumbnail, callback) | ||
278 | } | ||
279 | |||
280 | function createPreview (videoPath, callback) { | ||
281 | const filename = pathUtils.basename(videoPath) + '.jpg' | ||
282 | ffmpeg(videoPath) | ||
283 | .on('error', callback) | ||
284 | .on('end', function () { | ||
285 | callback(null, filename) | ||
286 | }) | ||
287 | .thumbnail({ | ||
288 | count: 1, | ||
289 | folder: constants.CONFIG.STORAGE.PREVIEWS_DIR, | ||
290 | filename: filename | ||
291 | }) | ||
292 | } | ||
293 | |||
269 | function createThumbnail (videoPath, callback) { | 294 | function createThumbnail (videoPath, callback) { |
270 | const filename = pathUtils.basename(videoPath) + '.jpg' | 295 | const filename = pathUtils.basename(videoPath) + '.jpg' |
271 | ffmpeg(videoPath) | 296 | ffmpeg(videoPath) |