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