]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/controllers/api/v1/videos.js
Update disk size for 1000000 videos in architecture
[github/Chocobozzz/PeerTube.git] / server / controllers / api / v1 / videos.js
1 'use strict'
2
3 const async = require('async')
4 const config = require('config')
5 const express = require('express')
6 const fs = require('fs')
7 const path = require('path')
8 const multer = require('multer')
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 oAuth2 = middlewares.oauth2
15 const pagination = middlewares.pagination
16 const reqValidator = middlewares.reqValidators
17 const reqValidatorPagination = reqValidator.pagination
18 const reqValidatorVideos = reqValidator.videos
19 const utils = require('../../../helpers/utils')
20 const Videos = require('../../../models/videos') // model
21 const videos = require('../../../lib/videos')
22 const webtorrent = require('../../../lib/webtorrent')
23
24 const router = express.Router()
25 const uploads = config.get('storage.uploads')
26
27 // multer configuration
28 const storage = multer.diskStorage({
29 destination: function (req, file, cb) {
30 cb(null, uploads)
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 const thumbnailsDir = path.join(__dirname, '..', '..', '..', '..', config.get('storage.thumbnails'))
47
48 router.get('/',
49 reqValidatorPagination.pagination,
50 pagination.setPagination,
51 listVideos
52 )
53 router.post('/',
54 oAuth2.authenticate,
55 reqFiles,
56 reqValidatorVideos.videosAdd,
57 addVideo
58 )
59 router.get('/:id',
60 reqValidatorVideos.videosGet,
61 getVideos
62 )
63 router.delete('/:id',
64 oAuth2.authenticate,
65 reqValidatorVideos.videosRemove,
66 removeVideo
67 )
68 router.get('/search/:name',
69 reqValidatorVideos.videosSearch,
70 reqValidatorPagination.pagination,
71 pagination.setPagination,
72 searchVideos
73 )
74
75 // ---------------------------------------------------------------------------
76
77 module.exports = router
78
79 // ---------------------------------------------------------------------------
80
81 function addVideo (req, res, next) {
82 const videoFile = req.files.videofile[0]
83 const videoInfos = req.body
84
85 async.waterfall([
86 function (callback) {
87 videos.seed(videoFile.path, callback)
88 },
89
90 function seed (torrent, callback) {
91 videos.getVideoDuration(videoFile.path, function (err, duration) {
92 if (err) {
93 // TODO: unseed the video
94 logger.error('Cannot retrieve metadata of the file.')
95 return next(err)
96 }
97
98 callback(null, torrent, duration)
99 })
100 },
101
102 function createThumbnail (torrent, duration, callback) {
103 videos.createVideoThumbnail(videoFile.path, function (err, thumbnailName) {
104 if (err) {
105 // TODO: unseed the video
106 logger.error('Cannot make a thumbnail of the video file.')
107 return callback(err)
108 }
109
110 callback(null, torrent, duration, thumbnailName)
111 })
112 },
113
114 function insertIntoDB (torrent, duration, thumbnailName, callback) {
115 const videoData = {
116 name: videoInfos.name,
117 namePath: videoFile.filename,
118 description: videoInfos.description,
119 magnetUri: torrent.magnetURI,
120 author: res.locals.oauth.token.user.username,
121 duration: duration,
122 thumbnail: thumbnailName
123 }
124
125 Videos.add(videoData, function (err, insertedVideo) {
126 if (err) {
127 // TODO unseed the video
128 // TODO remove thumbnail
129 logger.error('Cannot insert this video in the database.')
130 return callback(err)
131 }
132
133 return callback(null, torrent, duration, thumbnailName, videoData, insertedVideo)
134 })
135 },
136
137 function getThumbnailBase64 (torrent, duration, thumbnailName, videoData, insertedVideo, callback) {
138 videoData.createdDate = insertedVideo.createdDate
139
140 fs.readFile(thumbnailsDir + thumbnailName, function (err, thumbnailData) {
141 if (err) {
142 // TODO unseed the video
143 // TODO remove thumbnail
144 // TODO: remove video
145 logger.error('Cannot read the thumbnail of the video')
146 return callback(err)
147 }
148
149 return callback(null, videoData, thumbnailData)
150 })
151 },
152
153 function sendToFriends (videoData, thumbnailData, callback) {
154 // Set the image in base64
155 videoData.thumbnailBase64 = new Buffer(thumbnailData).toString('base64')
156
157 // Now we'll add the video's meta data to our friends
158 friends.addVideoToFriends(videoData)
159
160 return callback(null)
161 }
162
163 ], function (err) {
164 if (err) {
165 logger.error('Cannot insert the video.')
166 return next(err)
167 }
168
169 // TODO : include Location of the new video -> 201
170 return res.type('json').status(204).end()
171 })
172 }
173
174 function getVideos (req, res, next) {
175 Videos.get(req.params.id, function (err, videoObj) {
176 if (err) return next(err)
177
178 const state = videos.getVideoState(videoObj)
179 if (state.exist === false) {
180 return res.type('json').status(204).end()
181 }
182
183 res.json(getFormatedVideo(videoObj))
184 })
185 }
186
187 function listVideos (req, res, next) {
188 Videos.list(req.query.start, req.query.count, function (err, videosList) {
189 if (err) return next(err)
190
191 res.json(getFormatedVideos(videosList))
192 })
193 }
194
195 function removeVideo (req, res, next) {
196 const videoId = req.params.id
197
198 async.waterfall([
199 function getVideo (callback) {
200 Videos.get(videoId, callback)
201 },
202
203 function removeVideoTorrent (video, callback) {
204 removeTorrent(video.magnetUri, function () {
205 return callback(null, video)
206 })
207 },
208
209 function removeFromDB (video, callback) {
210 Videos.removeOwned(req.params.id, function (err) {
211 if (err) return callback(err)
212
213 return callback(null, video)
214 })
215 },
216
217 function removeVideoData (video, callback) {
218 videos.removeVideosDataFromDisk([ video ], function (err) {
219 if (err) logger.error('Cannot remove video data from disk.', { video: video })
220
221 return callback(null, video)
222 })
223 },
224
225 function sendInformationToFriends (video, callback) {
226 const params = {
227 name: video.name,
228 magnetUri: video.magnetUri
229 }
230
231 friends.removeVideoToFriends(params)
232
233 return callback(null)
234 }
235 ], function (err) {
236 if (err) {
237 logger.error('Errors when removed the video.', { error: err })
238 return next(err)
239 }
240
241 return res.type('json').status(204).end()
242 })
243 }
244
245 function searchVideos (req, res, next) {
246 Videos.search(req.params.name, req.query.start, req.query.count, function (err, videosList) {
247 if (err) return next(err)
248
249 res.json(getFormatedVideos(videosList))
250 })
251 }
252
253 // ---------------------------------------------------------------------------
254
255 function getFormatedVideo (videoObj) {
256 const formatedVideo = {
257 id: videoObj._id,
258 name: videoObj.name,
259 description: videoObj.description,
260 podUrl: videoObj.podUrl,
261 isLocal: videos.getVideoState(videoObj).owned,
262 magnetUri: videoObj.magnetUri,
263 author: videoObj.author,
264 duration: videoObj.duration,
265 thumbnailPath: constants.THUMBNAILS_STATIC_PATH + '/' + videoObj.thumbnail,
266 createdDate: videoObj.createdDate
267 }
268
269 return formatedVideo
270 }
271
272 function getFormatedVideos (videosObj) {
273 const formatedVideos = []
274
275 videosObj.forEach(function (videoObj) {
276 formatedVideos.push(getFormatedVideo(videoObj))
277 })
278
279 return formatedVideos
280 }
281
282 // Maybe the torrent is not seeded, but we catch the error to don't stop the removing process
283 function removeTorrent (magnetUri, callback) {
284 try {
285 webtorrent.remove(magnetUri, callback)
286 } catch (err) {
287 logger.warn('Cannot remove the torrent from WebTorrent', { err: err })
288 return callback(null)
289 }
290 }