5711c5657b1331930677ee76354aa7532bc7f48b
[oweals/peertube.git] / models / videos.js
1 ;(function () {
2   'use strict'
3
4   var async = require('async')
5   var config = require('config')
6   var dz = require('dezalgo')
7   var fs = require('fs')
8   var webtorrent = require('../lib/webTorrentNode')
9
10   var logger = require('../helpers/logger')
11   var pods = require('./pods')
12   var VideosDB = require('../initializers/database').VideosDB
13
14   var http = config.get('webserver.https') === true ? 'https' : 'http'
15   var host = config.get('webserver.host')
16   var port = config.get('webserver.port')
17
18   var videos = {
19     add: add,
20     addRemotes: addRemotes,
21     get: get,
22     list: list,
23     listOwned: listOwned,
24     remove: remove,
25     removeAllRemotes: removeAllRemotes,
26     removeAllRemotesOf: removeAllRemotesOf,
27     removeRemotes: removeRemotes,
28     search: search,
29     seedAll: seedAll,
30     uploadDir: uploadDir
31   }
32
33   // ----------- Public attributes ----------
34   var uploadDir = __dirname + '/../' + config.get('storage.uploads')
35
36   function add (data, callback) {
37     var video_file = data.video
38     var video_data = data.data
39
40     logger.info('Adding %s video.', video_file.path)
41     seedVideo(video_file.path, function (err, torrent) {
42       if (err) {
43         logger.error('Cannot seed this video.', { error: err })
44         return callback(err)
45       }
46
47       var params = {
48         name: video_data.name,
49         namePath: video_file.filename,
50         description: video_data.description,
51         magnetUri: torrent.magnetURI,
52         podUrl: http + '://' + host + ':' + port
53       }
54
55       VideosDB.create(params, function (err, video) {
56         if (err) {
57           logger.error('Cannot insert this video.', { error: err })
58           return callback(err)
59         }
60
61         // Now we'll add the video's meta data to our friends
62         params.namePath = null
63
64         pods.addVideoToFriends(params)
65         callback(null)
66       })
67     })
68   }
69
70   // TODO: avoid doublons
71   function addRemotes (videos, callback) {
72     if (callback === undefined) callback = function () {}
73
74     var to_add = []
75
76     async.each(videos, function (video, callback_each) {
77       callback_each = dz(callback_each)
78       logger.debug('Add remote video from pod: %s', video.podUrl)
79
80       var params = {
81         name: video.name,
82         namePath: null,
83         description: video.description,
84         magnetUri: video.magnetUri,
85         podUrl: video.podUrl
86       }
87
88       to_add.push(params)
89
90       callback_each()
91     }, function () {
92       VideosDB.create(to_add, function (err, videos) {
93         if (err) {
94           logger.error('Cannot insert this remote video.', { error: err })
95           return callback(err)
96         }
97
98         return callback(null, videos)
99       })
100     })
101   }
102
103   function get (id, callback) {
104     VideosDB.findById(id, function (err, video) {
105       if (err) {
106         logger.error('Cannot get this video.', { error: err })
107         return callback(err)
108       }
109
110       return callback(null, video)
111     })
112   }
113
114   function list (callback) {
115     VideosDB.find(function (err, videos_list) {
116       if (err) {
117         logger.error('Cannot get list of the videos.', { error: err })
118         return callback(err)
119       }
120
121       return callback(null, videos_list)
122     })
123   }
124
125   function listOwned (callback) {
126     // If namePath is not null this is *our* video
127     VideosDB.find({ namePath: { $ne: null } }, function (err, videos_list) {
128       if (err) {
129         logger.error('Cannot get list of the videos.', { error: err })
130         return callback(err)
131       }
132
133       return callback(null, videos_list)
134     })
135   }
136
137   function remove (id, callback) {
138     // Maybe the torrent is not seeded, but we catch the error to don't stop the removing process
139     function removeTorrent (magnetUri, callback) {
140       try {
141         webtorrent.remove(magnetUri, callback)
142       } catch (err) {
143         logger.warn('Cannot remove the torrent from WebTorrent', { err: err })
144         return callback(null)
145       }
146     }
147
148     VideosDB.findById(id, function (err, video) {
149       if (err || !video) {
150         if (!err) err = new Error('Cannot find this video.')
151         logger.error('Cannot find this video.', { error: err })
152         return callback(err)
153       }
154
155       if (video.namePath === null) {
156         var error_string = 'Cannot remove the video of another pod.'
157         logger.error(error_string)
158         return callback(new Error(error_string))
159       }
160
161       logger.info('Removing %s video', video.name)
162
163       removeTorrent(video.magnetUri, function () {
164         VideosDB.findByIdAndRemove(id, function (err) {
165           if (err) {
166             logger.error('Cannot remove the torrent.', { error: err })
167             return callback(err)
168           }
169
170           fs.unlink(uploadDir + video.namePath, function (err) {
171             if (err) {
172               logger.error('Cannot remove this video file.', { error: err })
173               return callback(err)
174             }
175
176             var params = {
177               name: video.name,
178               magnetUri: video.magnetUri
179             }
180
181             pods.removeVideoToFriends(params)
182             callback(null)
183           })
184         })
185       })
186     })
187   }
188
189   function removeAllRemotes (callback) {
190     VideosDB.remove({ namePath: null }, function (err) {
191       if (err) return callback(err)
192
193       callback(null)
194     })
195   }
196
197   function removeAllRemotesOf (fromUrl, callback) {
198     VideosDB.remove({ podUrl: fromUrl }, function (err) {
199       if (err) return callback(err)
200
201       callback(null)
202     })
203   }
204
205   // Use the magnet Uri because the _id field is not the same on different servers
206   function removeRemotes (fromUrl, magnetUris, callback) {
207     if (callback === undefined) callback = function () {}
208
209     VideosDB.find({ magnetUri: { $in: magnetUris } }, function (err, videos) {
210       if (err || !videos) {
211         logger.error('Cannot find the torrent URI of these remote videos.')
212         return callback(err)
213       }
214
215       var to_remove = []
216       async.each(videos, function (video, callback_async) {
217         callback_async = dz(callback_async)
218
219         if (video.podUrl !== fromUrl) {
220           logger.error('The pod %s has not the rights on the video of %s.', fromUrl, video.podUrl)
221         } else {
222           to_remove.push(video._id)
223         }
224
225         callback_async()
226       }, function () {
227         VideosDB.remove({ _id: { $in: to_remove } }, function (err) {
228           if (err) {
229             logger.error('Cannot remove the remote videos.')
230             return callback(err)
231           }
232
233           logger.info('Removed remote videos from %s.', fromUrl)
234           callback(null)
235         })
236       })
237     })
238   }
239
240   function search (name, callback) {
241     VideosDB.find({ name: new RegExp(name) }, function (err, videos) {
242       if (err) {
243         logger.error('Cannot search the videos.', { error: err })
244         return callback(err)
245       }
246
247       return callback(null, videos)
248     })
249   }
250
251   function seedAll (callback) {
252     VideosDB.find({ namePath: { $ne: null } }, function (err, videos_list) {
253       if (err) {
254         logger.error('Cannot get list of the videos to seed.', { error: err })
255         return callback(err)
256       }
257
258       async.each(videos_list, function (video, each_callback) {
259         seedVideo(uploadDir + video.namePath, function (err) {
260           if (err) {
261             logger.error('Cannot seed this video.', { error: err })
262             return callback(err)
263           }
264
265           each_callback(null)
266         })
267       }, callback)
268     })
269   }
270
271   // ---------------------------------------------------------------------------
272
273   module.exports = videos
274
275   // ---------------------------------------------------------------------------
276
277   function seedVideo (path, callback) {
278     logger.info('Seeding %s...', path)
279
280     webtorrent.seed(path, function (torrent) {
281       logger.info('%s seeded (%s).', path, torrent.magnetURI)
282
283       return callback(null, torrent)
284     })
285   }
286 })()