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