3 const eachSeries = require('async/eachSeries')
4 const express = require('express')
5 const waterfall = require('async/waterfall')
7 const db = require('../../initializers/database')
8 const middlewares = require('../../middlewares')
9 const secureMiddleware = middlewares.secure
10 const validators = middlewares.validators.remote
11 const logger = require('../../helpers/logger')
13 const router = express.Router()
15 router.post('/videos',
17 secureMiddleware.checkSignature,
18 validators.remoteVideos,
22 // ---------------------------------------------------------------------------
24 module.exports = router
26 // ---------------------------------------------------------------------------
28 function remoteVideos (req, res, next) {
29 const requests = req.body.data
30 const fromPod = res.locals.secure.pod
32 // We need to process in the same order to keep consistency
34 eachSeries(requests, function (request, callbackEach) {
35 const videoData = request.data
37 switch (request.type) {
39 addRemoteVideo(videoData, fromPod, callbackEach)
43 updateRemoteVideo(videoData, fromPod, callbackEach)
47 removeRemoteVideo(videoData, fromPod, callbackEach)
51 logger.error('Unkown remote request type %s.', request.type)
54 if (err) logger.error('Error managing remote videos.', { error: err })
57 // We don't need to keep the other pod waiting
58 return res.type('json').status(204).end()
61 function addRemoteVideo (videoToCreateData, fromPod, finalCallback) {
62 logger.debug('Adding remote video "%s".', videoToCreateData.name)
66 function startTransaction (callback) {
67 db.sequelize.transaction().asCallback(function (err, t) {
68 return callback(err, t)
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
78 db.Author.findOrCreateAuthor(name, podId, userId, t, function (err, authorInstance) {
79 return callback(err, t, authorInstance)
83 function findOrCreateTags (t, author, callback) {
84 const tags = videoToCreateData.tags
86 db.Tag.findOrCreateTags(tags, t, function (err, tagInstances) {
87 return callback(err, t, author, tagInstances)
91 function createVideoObject (t, author, tagInstances, callback) {
93 name: videoToCreateData.name,
94 remoteId: videoToCreateData.remoteId,
95 extname: videoToCreateData.extname,
96 infoHash: videoToCreateData.infoHash,
97 description: videoToCreateData.description,
99 duration: videoToCreateData.duration,
100 createdAt: videoToCreateData.createdAt,
101 updatedAt: videoToCreateData.updatedAt
104 const video = db.Video.build(videoData)
106 return callback(null, t, tagInstances, video)
109 function generateThumbnail (t, tagInstances, video, callback) {
110 db.Video.generateThumbnailFromData(video, videoToCreateData.thumbnailData, function (err) {
112 logger.error('Cannot generate thumbnail from data.', { error: err })
116 return callback(err, t, tagInstances, video)
120 function insertVideoIntoDB (t, tagInstances, video, callback) {
125 video.save(options).asCallback(function (err, videoCreated) {
126 return callback(err, t, tagInstances, videoCreated)
130 function associateTagsToVideo (t, tagInstances, video, callback) {
131 const options = { transaction: t }
133 video.setTags(tagInstances, options).asCallback(function (err) {
134 return callback(err, t)
138 ], function (err, t) {
140 logger.error('Cannot insert the remote video.')
142 // Abort transaction?
145 return finalCallback(err)
148 // Commit transaction
151 return finalCallback()
155 function updateRemoteVideo (videoAttributesToUpdate, fromPod, finalCallback) {
156 logger.debug('Updating remote video "%s".', videoAttributesToUpdate.name)
160 function startTransaction (callback) {
161 db.sequelize.transaction().asCallback(function (err, t) {
162 return callback(err, t)
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 })
173 return callback(null, t, videoInstance)
177 function findOrCreateTags (t, videoInstance, callback) {
178 const tags = videoAttributesToUpdate.tags
180 db.Tag.findOrCreateTags(tags, t, function (err, tagInstances) {
181 return callback(err, t, videoInstance, tagInstances)
185 function updateVideoIntoDB (t, videoInstance, tagInstances, callback) {
186 const options = { transaction: t }
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)
196 videoInstance.save(options).asCallback(function (err) {
197 return callback(err, t, videoInstance, tagInstances)
201 function associateTagsToVideo (t, videoInstance, tagInstances, callback) {
202 const options = { transaction: t }
204 videoInstance.setTags(tagInstances, options).asCallback(function (err) {
205 return callback(err, t)
209 ], function (err, t) {
211 logger.error('Cannot update the remote video.')
213 // Abort transaction?
216 return finalCallback(err)
219 // Commit transaction
222 return finalCallback()
226 function 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) {
230 logger.error('Cannot load video from host and remote id.', { error: err.message })
234 logger.debug('Removing remote video %s.', video.remoteId)
235 video.destroy().asCallback(callback)