]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/controllers/api/videos.js
Server: rename Pods -> Pod
[github/Chocobozzz/PeerTube.git] / server / controllers / api / videos.js
CommitLineData
9f10b292
C
1'use strict'
2
f0f5567b 3const express = require('express')
558d7c23 4const fs = require('fs')
f0f5567b 5const multer = require('multer')
558d7c23 6const path = require('path')
1a42c9e2 7const waterfall = require('async/waterfall')
f0f5567b 8
f253b1c1 9const constants = require('../../initializers/constants')
feb4bdfd 10const db = require('../../initializers/database')
f253b1c1
C
11const logger = require('../../helpers/logger')
12const friends = require('../../lib/friends')
13const middlewares = require('../../middlewares')
69b0a27c 14const oAuth = middlewares.oauth
fbf1134e 15const pagination = middlewares.pagination
fc51fde0
C
16const validators = middlewares.validators
17const validatorsPagination = validators.pagination
18const validatorsSort = validators.sort
19const validatorsVideos = validators.videos
46246b5f 20const search = middlewares.search
a877d5ac 21const sort = middlewares.sort
f253b1c1 22const utils = require('../../helpers/utils')
f0f5567b
C
23
24const router = express.Router()
9f10b292
C
25
26// multer configuration
f0f5567b 27const storage = multer.diskStorage({
9f10b292 28 destination: function (req, file, cb) {
b3d92510 29 cb(null, constants.CONFIG.STORAGE.VIDEOS_DIR)
9f10b292
C
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 }])
8c308c2b 45
fbf1134e 46router.get('/',
fc51fde0
C
47 validatorsPagination.pagination,
48 validatorsSort.videosSort,
a877d5ac 49 sort.setVideosSort,
fbf1134e
C
50 pagination.setPagination,
51 listVideos
52)
53router.post('/',
69b0a27c 54 oAuth.authenticate,
fbf1134e 55 reqFiles,
fc51fde0 56 validatorsVideos.videosAdd,
fbf1134e
C
57 addVideo
58)
59router.get('/:id',
fc51fde0 60 validatorsVideos.videosGet,
68ce3ae0 61 getVideo
fbf1134e
C
62)
63router.delete('/:id',
69b0a27c 64 oAuth.authenticate,
fc51fde0 65 validatorsVideos.videosRemove,
fbf1134e
C
66 removeVideo
67)
46246b5f 68router.get('/search/:value',
fc51fde0
C
69 validatorsVideos.videosSearch,
70 validatorsPagination.pagination,
71 validatorsSort.videosSort,
a877d5ac 72 sort.setVideosSort,
fbf1134e 73 pagination.setPagination,
46246b5f 74 search.setVideosSearch,
fbf1134e
C
75 searchVideos
76)
8c308c2b 77
9f10b292 78// ---------------------------------------------------------------------------
c45f7f84 79
9f10b292 80module.exports = router
c45f7f84 81
9f10b292 82// ---------------------------------------------------------------------------
c45f7f84 83
9f10b292 84function addVideo (req, res, next) {
bc503c2a
C
85 const videoFile = req.files.videofile[0]
86 const videoInfos = req.body
9f10b292 87
1a42c9e2 88 waterfall([
807df9e6 89
feb4bdfd
C
90 function findOrCreateAuthor (callback) {
91 const username = res.locals.oauth.token.user.username
92
93 const query = {
94 where: {
95 name: username,
96 podId: null
97 },
98 defaults: {
99 name: username,
100 podId: null // null because it is OUR pod
101 }
102 }
103
104 db.Author.findOrCreate(query).asCallback(function (err, result) {
105 // [ instance, wasCreated ]
106 return callback(err, result[0])
107 })
108 },
109
110 function createVideoObject (author, callback) {
807df9e6
C
111 const videoData = {
112 name: videoInfos.name,
558d7c23
C
113 remoteId: null,
114 extname: path.extname(videoFile.filename),
807df9e6 115 description: videoInfos.description,
67100f1f 116 duration: videoFile.duration,
feb4bdfd
C
117 tags: videoInfos.tags,
118 authorId: author.id
807df9e6
C
119 }
120
feb4bdfd 121 const video = db.Video.build(videoData)
558d7c23 122
feb4bdfd 123 return callback(null, author, video)
558d7c23
C
124 },
125
feb4bdfd
C
126 // Set the videoname the same as the id
127 function renameVideoFile (author, video, callback) {
558d7c23
C
128 const videoDir = constants.CONFIG.STORAGE.VIDEOS_DIR
129 const source = path.join(videoDir, videoFile.filename)
f285faa0 130 const destination = path.join(videoDir, video.getVideoFilename())
558d7c23
C
131
132 fs.rename(source, destination, function (err) {
feb4bdfd 133 return callback(err, author, video)
558d7c23
C
134 })
135 },
136
feb4bdfd
C
137 function insertIntoDB (author, video, callback) {
138 video.save().asCallback(function (err, videoCreated) {
139 // Do not forget to add Author informations to the created video
140 videoCreated.Author = author
141
142 return callback(err, videoCreated)
3a8a8b51 143 })
807df9e6
C
144 },
145
aaf61f38
C
146 function sendToFriends (video, callback) {
147 video.toRemoteJSON(function (err, remoteVideo) {
148 if (err) return callback(err)
807df9e6 149
528a9efa
C
150 // Now we'll add the video's meta data to our friends
151 friends.addVideoToFriends(remoteVideo)
807df9e6 152
528a9efa
C
153 return callback(null)
154 })
807df9e6
C
155 }
156
be587647 157 ], function andFinally (err) {
807df9e6
C
158 if (err) {
159 logger.error('Cannot insert the video.')
160 return next(err)
161 }
162
163 // TODO : include Location of the new video -> 201
164 return res.type('json').status(204).end()
9f10b292
C
165 })
166}
8c308c2b 167
68ce3ae0 168function getVideo (req, res, next) {
feb4bdfd 169 db.Video.loadAndPopulateAuthorAndPod(req.params.id, function (err, video) {
9f10b292 170 if (err) return next(err)
8c308c2b 171
aaf61f38 172 if (!video) {
2df82d42 173 return res.type('json').status(204).end()
9f10b292 174 }
8c308c2b 175
aaf61f38 176 res.json(video.toFormatedJSON())
9f10b292
C
177 })
178}
8c308c2b 179
9f10b292 180function listVideos (req, res, next) {
feb4bdfd 181 db.Video.listForApi(req.query.start, req.query.count, req.query.sort, function (err, videosList, videosTotal) {
9f10b292 182 if (err) return next(err)
c45f7f84 183
aaf61f38 184 res.json(getFormatedVideos(videosList, videosTotal))
9f10b292
C
185 })
186}
c45f7f84 187
9f10b292 188function removeVideo (req, res, next) {
bc503c2a 189 const videoId = req.params.id
8c308c2b 190
1a42c9e2 191 waterfall([
807df9e6 192 function getVideo (callback) {
feb4bdfd 193 db.Video.load(videoId, callback)
807df9e6
C
194 },
195
196 function removeFromDB (video, callback) {
feb4bdfd 197 video.destroy().asCallback(function (err) {
807df9e6 198 if (err) return callback(err)
c173e565 199
807df9e6
C
200 return callback(null, video)
201 })
202 },
cbe2f7c3 203
807df9e6
C
204 function sendInformationToFriends (video, callback) {
205 const params = {
206 name: video.name,
feb4bdfd 207 remoteId: video.id
807df9e6
C
208 }
209
210 friends.removeVideoToFriends(params)
211
212 return callback(null)
213 }
be587647 214 ], function andFinally (err) {
807df9e6
C
215 if (err) {
216 logger.error('Errors when removed the video.', { error: err })
217 return next(err)
218 }
219
220 return res.type('json').status(204).end()
9f10b292
C
221 })
222}
8c308c2b 223
9f10b292 224function searchVideos (req, res, next) {
feb4bdfd 225 db.Video.searchAndPopulateAuthorAndPod(req.params.value, req.query.field, req.query.start, req.query.count, req.query.sort,
aaf61f38 226 function (err, videosList, videosTotal) {
9f10b292 227 if (err) return next(err)
8c308c2b 228
aaf61f38 229 res.json(getFormatedVideos(videosList, videosTotal))
9f10b292
C
230 })
231}
c173e565 232
9f10b292 233// ---------------------------------------------------------------------------
c173e565 234
aaf61f38 235function getFormatedVideos (videos, videosTotal) {
bc503c2a 236 const formatedVideos = []
2df82d42 237
aaf61f38
C
238 videos.forEach(function (video) {
239 formatedVideos.push(video.toFormatedJSON())
2df82d42
C
240 })
241
68ce3ae0 242 return {
aaf61f38 243 total: videosTotal,
68ce3ae0
C
244 data: formatedVideos
245 }
2df82d42 246}