daf452573f05cce6e78cc4fedfa470e59d108ef2
[oweals/peertube.git] / server / controllers / api / videos.js
1 'use strict'
2
3 const express = require('express')
4 const fs = require('fs')
5 const mongoose = require('mongoose')
6 const multer = require('multer')
7 const path = require('path')
8 const waterfall = require('async/waterfall')
9
10 const constants = require('../../initializers/constants')
11 const logger = require('../../helpers/logger')
12 const friends = require('../../lib/friends')
13 const middlewares = require('../../middlewares')
14 const oAuth = middlewares.oauth
15 const pagination = middlewares.pagination
16 const validators = middlewares.validators
17 const validatorsPagination = validators.pagination
18 const validatorsSort = validators.sort
19 const validatorsVideos = validators.videos
20 const search = middlewares.search
21 const sort = middlewares.sort
22 const utils = require('../../helpers/utils')
23
24 const router = express.Router()
25 const Video = mongoose.model('Video')
26
27 // multer configuration
28 const storage = multer.diskStorage({
29   destination: function (req, file, cb) {
30     cb(null, constants.CONFIG.STORAGE.VIDEOS_DIR)
31   },
32
33   filename: function (req, file, cb) {
34     let extension = ''
35     if (file.mimetype === 'video/webm') extension = 'webm'
36     else if (file.mimetype === 'video/mp4') extension = 'mp4'
37     else if (file.mimetype === 'video/ogg') extension = 'ogv'
38     utils.generateRandomString(16, function (err, randomString) {
39       const fieldname = err ? undefined : randomString
40       cb(null, fieldname + '.' + extension)
41     })
42   }
43 })
44
45 const reqFiles = multer({ storage: storage }).fields([{ name: 'videofile', maxCount: 1 }])
46
47 router.get('/',
48   validatorsPagination.pagination,
49   validatorsSort.videosSort,
50   sort.setVideosSort,
51   pagination.setPagination,
52   listVideos
53 )
54 router.post('/',
55   oAuth.authenticate,
56   reqFiles,
57   validatorsVideos.videosAdd,
58   addVideo
59 )
60 router.get('/:id',
61   validatorsVideos.videosGet,
62   getVideo
63 )
64 router.delete('/:id',
65   oAuth.authenticate,
66   validatorsVideos.videosRemove,
67   removeVideo
68 )
69 router.get('/search/:value',
70   validatorsVideos.videosSearch,
71   validatorsPagination.pagination,
72   validatorsSort.videosSort,
73   sort.setVideosSort,
74   pagination.setPagination,
75   search.setVideosSearch,
76   searchVideos
77 )
78
79 // ---------------------------------------------------------------------------
80
81 module.exports = router
82
83 // ---------------------------------------------------------------------------
84
85 function addVideo (req, res, next) {
86   const videoFile = req.files.videofile[0]
87   const videoInfos = req.body
88
89   waterfall([
90     function createVideoObject (callback) {
91       const id = mongoose.Types.ObjectId()
92
93       const videoData = {
94         _id: id,
95         name: videoInfos.name,
96         remoteId: null,
97         extname: path.extname(videoFile.filename),
98         description: videoInfos.description,
99         author: res.locals.oauth.token.user.username,
100         duration: videoFile.duration,
101         tags: videoInfos.tags
102       }
103
104       const video = new Video(videoData)
105
106       return callback(null, video)
107     },
108
109      // Set the videoname the same as the MongoDB id
110     function renameVideoFile (video, callback) {
111       const videoDir = constants.CONFIG.STORAGE.VIDEOS_DIR
112       const source = path.join(videoDir, videoFile.filename)
113       const destination = path.join(videoDir, video.getVideoFilename())
114
115       fs.rename(source, destination, function (err) {
116         return callback(err, video)
117       })
118     },
119
120     function insertIntoDB (video, callback) {
121       video.save(function (err, video) {
122         // Assert there are only one argument sent to the next function (video)
123         return callback(err, video)
124       })
125     },
126
127     function sendToFriends (video, callback) {
128       video.toRemoteJSON(function (err, remoteVideo) {
129         if (err) return callback(err)
130
131         // Now we'll add the video's meta data to our friends
132         friends.addVideoToFriends(remoteVideo)
133
134         return callback(null)
135       })
136     }
137
138   ], function andFinally (err) {
139     if (err) {
140       logger.error('Cannot insert the video.')
141       return next(err)
142     }
143
144     // TODO : include Location of the new video -> 201
145     return res.type('json').status(204).end()
146   })
147 }
148
149 function getVideo (req, res, next) {
150   Video.load(req.params.id, function (err, video) {
151     if (err) return next(err)
152
153     if (!video) {
154       return res.type('json').status(204).end()
155     }
156
157     res.json(video.toFormatedJSON())
158   })
159 }
160
161 function listVideos (req, res, next) {
162   Video.listForApi(req.query.start, req.query.count, req.query.sort, function (err, videosList, videosTotal) {
163     if (err) return next(err)
164
165     res.json(getFormatedVideos(videosList, videosTotal))
166   })
167 }
168
169 function removeVideo (req, res, next) {
170   const videoId = req.params.id
171
172   waterfall([
173     function getVideo (callback) {
174       Video.load(videoId, callback)
175     },
176
177     function removeFromDB (video, callback) {
178       video.remove(function (err) {
179         if (err) return callback(err)
180
181         return callback(null, video)
182       })
183     },
184
185     function sendInformationToFriends (video, callback) {
186       const params = {
187         name: video.name,
188         remoteId: video._id
189       }
190
191       friends.removeVideoToFriends(params)
192
193       return callback(null)
194     }
195   ], function andFinally (err) {
196     if (err) {
197       logger.error('Errors when removed the video.', { error: err })
198       return next(err)
199     }
200
201     return res.type('json').status(204).end()
202   })
203 }
204
205 function searchVideos (req, res, next) {
206   Video.search(req.params.value, req.query.field, req.query.start, req.query.count, req.query.sort,
207   function (err, videosList, videosTotal) {
208     if (err) return next(err)
209
210     res.json(getFormatedVideos(videosList, videosTotal))
211   })
212 }
213
214 // ---------------------------------------------------------------------------
215
216 function getFormatedVideos (videos, videosTotal) {
217   const formatedVideos = []
218
219   videos.forEach(function (video) {
220     formatedVideos.push(video.toFormatedJSON())
221   })
222
223   return {
224     total: videosTotal,
225     data: formatedVideos
226   }
227 }