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