]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/controllers/api/v1/videos.js
641fef6ead3ef9d1e34e1b275ddc9cbcc9f004c1
[github/Chocobozzz/PeerTube.git] / server / controllers / api / v1 / videos.js
1 'use strict'
2
3 const config = require('config')
4 const express = require('express')
5 const fs = require('fs')
6 const path = require('path')
7 const multer = require('multer')
8
9 const constants = require('../../../initializers/constants')
10 const logger = require('../../../helpers/logger')
11 const friends = require('../../../lib/friends')
12 const middlewares = require('../../../middlewares')
13 const oAuth2 = middlewares.oauth2
14 const pagination = middlewares.pagination
15 const reqValidator = middlewares.reqValidators
16 const reqValidatorPagination = reqValidator.pagination
17 const reqValidatorVideos = reqValidator.videos
18 const utils = require('../../../helpers/utils')
19 const Videos = require('../../../models/videos') // model
20 const videos = require('../../../lib/videos')
21 const webtorrent = require('../../../lib/webtorrent')
22
23 const router = express.Router()
24 const uploads = config.get('storage.uploads')
25
26 // multer configuration
27 const storage = multer.diskStorage({
28 destination: function (req, file, cb) {
29 cb(null, uploads)
30 },
31
32 filename: function (req, file, cb) {
33 let extension = ''
34 if (file.mimetype === 'video/webm') extension = 'webm'
35 else if (file.mimetype === 'video/mp4') extension = 'mp4'
36 else if (file.mimetype === 'video/ogg') extension = 'ogv'
37 utils.generateRandomString(16, function (err, randomString) {
38 const fieldname = err ? undefined : randomString
39 cb(null, fieldname + '.' + extension)
40 })
41 }
42 })
43
44 const reqFiles = multer({ storage: storage }).fields([{ name: 'videofile', maxCount: 1 }])
45 const thumbnailsDir = path.join(__dirname, '..', '..', '..', '..', config.get('storage.thumbnails'))
46
47 router.get('/',
48 reqValidatorPagination.pagination,
49 pagination.setPagination,
50 listVideos
51 )
52 router.post('/',
53 oAuth2.authenticate,
54 reqFiles,
55 reqValidatorVideos.videosAdd,
56 addVideo
57 )
58 router.get('/:id',
59 reqValidatorVideos.videosGet,
60 getVideos
61 )
62 router.delete('/:id',
63 oAuth2.authenticate,
64 reqValidatorVideos.videosRemove,
65 removeVideo
66 )
67 router.get('/search/:name',
68 reqValidatorVideos.videosSearch,
69 reqValidatorPagination.pagination,
70 pagination.setPagination,
71 searchVideos
72 )
73
74 // ---------------------------------------------------------------------------
75
76 module.exports = router
77
78 // ---------------------------------------------------------------------------
79
80 function addVideo (req, res, next) {
81 const videoFile = req.files.videofile[0]
82 const videoInfos = req.body
83
84 videos.seed(videoFile.path, function (err, torrent) {
85 if (err) {
86 logger.error('Cannot seed this video.')
87 return next(err)
88 }
89
90 videos.getVideoDuration(videoFile.path, function (err, duration) {
91 if (err) {
92 // TODO: unseed the video
93 logger.error('Cannot retrieve metadata of the file.')
94 return next(err)
95 }
96
97 videos.createVideoThumbnail(videoFile.path, function (err, thumbnailName) {
98 if (err) {
99 // TODO: unseed the video
100 logger.error('Cannot make a thumbnail of the video file.')
101 return next(err)
102 }
103
104 const videoData = {
105 name: videoInfos.name,
106 namePath: videoFile.filename,
107 description: videoInfos.description,
108 magnetUri: torrent.magnetURI,
109 author: res.locals.oauth.token.user.username,
110 duration: duration,
111 thumbnail: thumbnailName
112 }
113
114 Videos.add(videoData, function (err, insertedVideo) {
115 if (err) {
116 // TODO unseed the video
117 logger.error('Cannot insert this video in the database.')
118 return next(err)
119 }
120
121 videoData.createdDate = insertedVideo.createdDate
122
123 fs.readFile(thumbnailsDir + thumbnailName, function (err, data) {
124 if (err) {
125 // TODO: remove video?
126 logger.error('Cannot read the thumbnail of the video')
127 return next(err)
128 }
129
130 // Set the image in base64
131 videoData.thumbnailBase64 = new Buffer(data).toString('base64')
132 // Now we'll add the video's meta data to our friends
133 friends.addVideoToFriends(videoData)
134
135 // TODO : include Location of the new video -> 201
136 res.type('json').status(204).end()
137 })
138 })
139 })
140 })
141 })
142 }
143
144 function getVideos (req, res, next) {
145 Videos.get(req.params.id, function (err, videoObj) {
146 if (err) return next(err)
147
148 const state = videos.getVideoState(videoObj)
149 if (state.exist === false) {
150 return res.type('json').status(204).end()
151 }
152
153 res.json(getFormatedVideo(videoObj))
154 })
155 }
156
157 function listVideos (req, res, next) {
158 Videos.list(req.query.start, req.query.count, function (err, videosList) {
159 if (err) return next(err)
160
161 res.json(getFormatedVideos(videosList))
162 })
163 }
164
165 function removeVideo (req, res, next) {
166 const videoId = req.params.id
167 Videos.get(videoId, function (err, video) {
168 if (err) return next(err)
169
170 removeTorrent(video.magnetUri, function () {
171 Videos.removeOwned(req.params.id, function (err) {
172 if (err) return next(err)
173
174 videos.removeVideosDataFromDisk([ video ], function (err) {
175 if (err) logger.error('Cannot remove video data from disk.', { video: video })
176
177 const params = {
178 name: video.name,
179 magnetUri: video.magnetUri
180 }
181
182 friends.removeVideoToFriends(params)
183 res.type('json').status(204).end()
184 })
185 })
186 })
187 })
188 }
189
190 function searchVideos (req, res, next) {
191 Videos.search(req.params.name, req.query.start, req.query.count, function (err, videosList) {
192 if (err) return next(err)
193
194 res.json(getFormatedVideos(videosList))
195 })
196 }
197
198 // ---------------------------------------------------------------------------
199
200 function getFormatedVideo (videoObj) {
201 const formatedVideo = {
202 id: videoObj._id,
203 name: videoObj.name,
204 description: videoObj.description,
205 podUrl: videoObj.podUrl,
206 isLocal: videos.getVideoState(videoObj).owned,
207 magnetUri: videoObj.magnetUri,
208 author: videoObj.author,
209 duration: videoObj.duration,
210 thumbnailPath: constants.THUMBNAILS_STATIC_PATH + '/' + videoObj.thumbnail,
211 createdDate: videoObj.createdDate
212 }
213
214 return formatedVideo
215 }
216
217 function getFormatedVideos (videosObj) {
218 const formatedVideos = []
219
220 videosObj.forEach(function (videoObj) {
221 formatedVideos.push(getFormatedVideo(videoObj))
222 })
223
224 return formatedVideos
225 }
226
227 // Maybe the torrent is not seeded, but we catch the error to don't stop the removing process
228 function removeTorrent (magnetUri, callback) {
229 try {
230 webtorrent.remove(magnetUri, callback)
231 } catch (err) {
232 logger.warn('Cannot remove the torrent from WebTorrent', { err: err })
233 return callback(null)
234 }
235 }