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