aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/controllers/api/remote
diff options
context:
space:
mode:
Diffstat (limited to 'server/controllers/api/remote')
-rw-r--r--server/controllers/api/remote/index.js16
-rw-r--r--server/controllers/api/remote/videos.js237
2 files changed, 253 insertions, 0 deletions
diff --git a/server/controllers/api/remote/index.js b/server/controllers/api/remote/index.js
new file mode 100644
index 000000000..2947632d5
--- /dev/null
+++ b/server/controllers/api/remote/index.js
@@ -0,0 +1,16 @@
1'use strict'
2
3const express = require('express')
4
5const utils = require('../../../helpers/utils')
6
7const router = express.Router()
8
9const videosRemoteController = require('./videos')
10
11router.use('/videos', videosRemoteController)
12router.use('/*', utils.badRequest)
13
14// ---------------------------------------------------------------------------
15
16module.exports = router
diff --git a/server/controllers/api/remote/videos.js b/server/controllers/api/remote/videos.js
new file mode 100644
index 000000000..87c49bff9
--- /dev/null
+++ b/server/controllers/api/remote/videos.js
@@ -0,0 +1,237 @@
1'use strict'
2
3const eachSeries = require('async/eachSeries')
4const express = require('express')
5const waterfall = require('async/waterfall')
6
7const db = require('../../../initializers/database')
8const middlewares = require('../../../middlewares')
9const secureMiddleware = middlewares.secure
10const validators = middlewares.validators.remote
11const logger = require('../../../helpers/logger')
12
13const router = express.Router()
14
15router.post('/',
16 validators.signature,
17 secureMiddleware.checkSignature,
18 validators.remoteVideos,
19 remoteVideos
20)
21
22// ---------------------------------------------------------------------------
23
24module.exports = router
25
26// ---------------------------------------------------------------------------
27
28function remoteVideos (req, res, next) {
29 const requests = req.body.data
30 const fromPod = res.locals.secure.pod
31
32 // We need to process in the same order to keep consistency
33 // TODO: optimization
34 eachSeries(requests, function (request, callbackEach) {
35 const videoData = request.data
36
37 switch (request.type) {
38 case 'add':
39 addRemoteVideo(videoData, fromPod, callbackEach)
40 break
41
42 case 'update':
43 updateRemoteVideo(videoData, fromPod, callbackEach)
44 break
45
46 case 'remove':
47 removeRemoteVideo(videoData, fromPod, callbackEach)
48 break
49
50 default:
51 logger.error('Unkown remote request type %s.', request.type)
52 }
53 }, function (err) {
54 if (err) logger.error('Error managing remote videos.', { error: err })
55 })
56
57 // We don't need to keep the other pod waiting
58 return res.type('json').status(204).end()
59}
60
61function addRemoteVideo (videoToCreateData, fromPod, finalCallback) {
62 logger.debug('Adding remote video "%s".', videoToCreateData.name)
63
64 waterfall([
65
66 function startTransaction (callback) {
67 db.sequelize.transaction().asCallback(function (err, t) {
68 return callback(err, t)
69 })
70 },
71
72 function findOrCreateAuthor (t, callback) {
73 const name = videoToCreateData.author
74 const podId = fromPod.id
75 // This author is from another pod so we do not associate a user
76 const userId = null
77
78 db.Author.findOrCreateAuthor(name, podId, userId, t, function (err, authorInstance) {
79 return callback(err, t, authorInstance)
80 })
81 },
82
83 function findOrCreateTags (t, author, callback) {
84 const tags = videoToCreateData.tags
85
86 db.Tag.findOrCreateTags(tags, t, function (err, tagInstances) {
87 return callback(err, t, author, tagInstances)
88 })
89 },
90
91 function createVideoObject (t, author, tagInstances, callback) {
92 const videoData = {
93 name: videoToCreateData.name,
94 remoteId: videoToCreateData.remoteId,
95 extname: videoToCreateData.extname,
96 infoHash: videoToCreateData.infoHash,
97 description: videoToCreateData.description,
98 authorId: author.id,
99 duration: videoToCreateData.duration,
100 createdAt: videoToCreateData.createdAt,
101 updatedAt: videoToCreateData.updatedAt
102 }
103
104 const video = db.Video.build(videoData)
105
106 return callback(null, t, tagInstances, video)
107 },
108
109 function generateThumbnail (t, tagInstances, video, callback) {
110 db.Video.generateThumbnailFromData(video, videoToCreateData.thumbnailData, function (err) {
111 if (err) {
112 logger.error('Cannot generate thumbnail from data.', { error: err })
113 return callback(err)
114 }
115
116 return callback(err, t, tagInstances, video)
117 })
118 },
119
120 function insertVideoIntoDB (t, tagInstances, video, callback) {
121 const options = {
122 transaction: t
123 }
124
125 video.save(options).asCallback(function (err, videoCreated) {
126 return callback(err, t, tagInstances, videoCreated)
127 })
128 },
129
130 function associateTagsToVideo (t, tagInstances, video, callback) {
131 const options = { transaction: t }
132
133 video.setTags(tagInstances, options).asCallback(function (err) {
134 return callback(err, t)
135 })
136 }
137
138 ], function (err, t) {
139 if (err) {
140 logger.error('Cannot insert the remote video.')
141
142 // Abort transaction?
143 if (t) t.rollback()
144
145 return finalCallback(err)
146 }
147
148 // Commit transaction
149 t.commit()
150
151 return finalCallback()
152 })
153}
154
155function updateRemoteVideo (videoAttributesToUpdate, fromPod, finalCallback) {
156 logger.debug('Updating remote video "%s".', videoAttributesToUpdate.name)
157
158 waterfall([
159
160 function startTransaction (callback) {
161 db.sequelize.transaction().asCallback(function (err, t) {
162 return callback(err, t)
163 })
164 },
165
166 function findVideo (t, callback) {
167 db.Video.loadByHostAndRemoteId(fromPod.host, videoAttributesToUpdate.remoteId, function (err, videoInstance) {
168 if (err || !videoInstance) {
169 logger.error('Cannot load video from host and remote id.', { error: err.message })
170 return callback(err)
171 }
172
173 return callback(null, t, videoInstance)
174 })
175 },
176
177 function findOrCreateTags (t, videoInstance, callback) {
178 const tags = videoAttributesToUpdate.tags
179
180 db.Tag.findOrCreateTags(tags, t, function (err, tagInstances) {
181 return callback(err, t, videoInstance, tagInstances)
182 })
183 },
184
185 function updateVideoIntoDB (t, videoInstance, tagInstances, callback) {
186 const options = { transaction: t }
187
188 videoInstance.set('name', videoAttributesToUpdate.name)
189 videoInstance.set('description', videoAttributesToUpdate.description)
190 videoInstance.set('infoHash', videoAttributesToUpdate.infoHash)
191 videoInstance.set('duration', videoAttributesToUpdate.duration)
192 videoInstance.set('createdAt', videoAttributesToUpdate.createdAt)
193 videoInstance.set('updatedAt', videoAttributesToUpdate.updatedAt)
194 videoInstance.set('extname', videoAttributesToUpdate.extname)
195
196 videoInstance.save(options).asCallback(function (err) {
197 return callback(err, t, videoInstance, tagInstances)
198 })
199 },
200
201 function associateTagsToVideo (t, videoInstance, tagInstances, callback) {
202 const options = { transaction: t }
203
204 videoInstance.setTags(tagInstances, options).asCallback(function (err) {
205 return callback(err, t)
206 })
207 }
208
209 ], function (err, t) {
210 if (err) {
211 logger.error('Cannot update the remote video.')
212
213 // Abort transaction?
214 if (t) t.rollback()
215
216 return finalCallback(err)
217 }
218
219 // Commit transaction
220 t.commit()
221
222 return finalCallback()
223 })
224}
225
226function removeRemoteVideo (videoToRemoveData, fromPod, callback) {
227 // We need the instance because we have to remove some other stuffs (thumbnail etc)
228 db.Video.loadByHostAndRemoteId(fromPod.host, videoToRemoveData.remoteId, function (err, video) {
229 if (err || !video) {
230 logger.error('Cannot load video from host and remote id.', { error: err.message })
231 return callback(err)
232 }
233
234 logger.debug('Removing remote video %s.', video.remoteId)
235 video.destroy().asCallback(callback)
236 })
237}