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