diff options
Diffstat (limited to 'server/models/video.js')
-rw-r--r-- | server/models/video.js | 102 |
1 files changed, 72 insertions, 30 deletions
diff --git a/server/models/video.js b/server/models/video.js index 6cffa87af..19136ba25 100644 --- a/server/models/video.js +++ b/server/models/video.js | |||
@@ -3,10 +3,10 @@ | |||
3 | const createTorrent = require('create-torrent') | 3 | const createTorrent = require('create-torrent') |
4 | const ffmpeg = require('fluent-ffmpeg') | 4 | const ffmpeg = require('fluent-ffmpeg') |
5 | const fs = require('fs') | 5 | const fs = require('fs') |
6 | const magnetUtil = require('magnet-uri') | ||
6 | const parallel = require('async/parallel') | 7 | const parallel = require('async/parallel') |
7 | const parseTorrent = require('parse-torrent') | 8 | const parseTorrent = require('parse-torrent') |
8 | const pathUtils = require('path') | 9 | const pathUtils = require('path') |
9 | const magnet = require('magnet-uri') | ||
10 | const mongoose = require('mongoose') | 10 | const mongoose = require('mongoose') |
11 | 11 | ||
12 | const constants = require('../initializers/constants') | 12 | const constants = require('../initializers/constants') |
@@ -25,7 +25,9 @@ const VideoSchema = mongoose.Schema({ | |||
25 | }, | 25 | }, |
26 | remoteId: mongoose.Schema.Types.ObjectId, | 26 | remoteId: mongoose.Schema.Types.ObjectId, |
27 | description: String, | 27 | description: String, |
28 | magnetUri: String, | 28 | magnet: { |
29 | infoHash: String | ||
30 | }, | ||
29 | podUrl: String, | 31 | podUrl: String, |
30 | author: String, | 32 | author: String, |
31 | duration: Number, | 33 | duration: Number, |
@@ -39,7 +41,6 @@ const VideoSchema = mongoose.Schema({ | |||
39 | 41 | ||
40 | VideoSchema.path('name').validate(customVideosValidators.isVideoNameValid) | 42 | VideoSchema.path('name').validate(customVideosValidators.isVideoNameValid) |
41 | VideoSchema.path('description').validate(customVideosValidators.isVideoDescriptionValid) | 43 | VideoSchema.path('description').validate(customVideosValidators.isVideoDescriptionValid) |
42 | VideoSchema.path('magnetUri').validate(customVideosValidators.isVideoMagnetUriValid) | ||
43 | VideoSchema.path('podUrl').validate(customVideosValidators.isVideoPodUrlValid) | 44 | VideoSchema.path('podUrl').validate(customVideosValidators.isVideoPodUrlValid) |
44 | VideoSchema.path('author').validate(customVideosValidators.isVideoAuthorValid) | 45 | VideoSchema.path('author').validate(customVideosValidators.isVideoAuthorValid) |
45 | VideoSchema.path('duration').validate(customVideosValidators.isVideoDurationValid) | 46 | VideoSchema.path('duration').validate(customVideosValidators.isVideoDurationValid) |
@@ -51,8 +52,10 @@ VideoSchema.path('thumbnail').validate(function (value) { | |||
51 | VideoSchema.path('tags').validate(customVideosValidators.isVideoTagsValid) | 52 | VideoSchema.path('tags').validate(customVideosValidators.isVideoTagsValid) |
52 | 53 | ||
53 | VideoSchema.methods = { | 54 | VideoSchema.methods = { |
54 | getFilename, | 55 | generateMagnetUri, |
55 | getJPEGName, | 56 | getVideoFilename, |
57 | getThumbnailName, | ||
58 | getPreviewName, | ||
56 | getTorrentName, | 59 | getTorrentName, |
57 | isOwned, | 60 | isOwned, |
58 | toFormatedJSON, | 61 | toFormatedJSON, |
@@ -103,8 +106,8 @@ VideoSchema.pre('save', function (next) { | |||
103 | const tasks = [] | 106 | const tasks = [] |
104 | 107 | ||
105 | if (video.isOwned()) { | 108 | if (video.isOwned()) { |
106 | const videoPath = pathUtils.join(constants.CONFIG.STORAGE.VIDEOS_DIR, video.getFilename()) | 109 | const videoPath = pathUtils.join(constants.CONFIG.STORAGE.VIDEOS_DIR, video.getVideoFilename()) |
107 | this.podUrl = constants.CONFIG.WEBSERVER.URL | 110 | this.podUrl = constants.CONFIG.WEBSERVER.HOSTNAME + ':' + constants.CONFIG.WEBSERVER.PORT |
108 | 111 | ||
109 | tasks.push( | 112 | tasks.push( |
110 | // TODO: refractoring | 113 | // TODO: refractoring |
@@ -114,7 +117,7 @@ VideoSchema.pre('save', function (next) { | |||
114 | [ constants.CONFIG.WEBSERVER.WS + '://' + constants.CONFIG.WEBSERVER.HOSTNAME + ':' + constants.CONFIG.WEBSERVER.PORT + '/tracker/socket' ] | 117 | [ constants.CONFIG.WEBSERVER.WS + '://' + constants.CONFIG.WEBSERVER.HOSTNAME + ':' + constants.CONFIG.WEBSERVER.PORT + '/tracker/socket' ] |
115 | ], | 118 | ], |
116 | urlList: [ | 119 | urlList: [ |
117 | constants.CONFIG.WEBSERVER.URL + constants.STATIC_PATHS.WEBSEED + video.getFilename() | 120 | constants.CONFIG.WEBSERVER.URL + constants.STATIC_PATHS.WEBSEED + video.getVideoFilename() |
118 | ] | 121 | ] |
119 | } | 122 | } |
120 | 123 | ||
@@ -125,9 +128,9 @@ VideoSchema.pre('save', function (next) { | |||
125 | if (err) return callback(err) | 128 | if (err) return callback(err) |
126 | 129 | ||
127 | const parsedTorrent = parseTorrent(torrent) | 130 | const parsedTorrent = parseTorrent(torrent) |
128 | parsedTorrent.xs = video.podUrl + constants.STATIC_PATHS.TORRENTS + video.getTorrentName() | 131 | video.magnet.infoHash = parsedTorrent.infoHash |
129 | video.magnetUri = magnet.encode(parsedTorrent) | ||
130 | 132 | ||
133 | console.log(parsedTorrent) | ||
131 | callback(null) | 134 | callback(null) |
132 | }) | 135 | }) |
133 | }) | 136 | }) |
@@ -150,16 +153,57 @@ mongoose.model('Video', VideoSchema) | |||
150 | 153 | ||
151 | // ------------------------------ METHODS ------------------------------ | 154 | // ------------------------------ METHODS ------------------------------ |
152 | 155 | ||
153 | function getFilename () { | 156 | function generateMagnetUri () { |
154 | return this._id + this.extname | 157 | let baseUrlHttp, baseUrlWs |
158 | |||
159 | if (this.isOwned()) { | ||
160 | baseUrlHttp = constants.CONFIG.WEBSERVER.URL | ||
161 | baseUrlWs = constants.CONFIG.WEBSERVER.WS + '://' + constants.CONFIG.WEBSERVER.HOSTNAME + ':' + constants.CONFIG.WEBSERVER.PORT | ||
162 | } else { | ||
163 | baseUrlHttp = constants.REMOTE_SCHEME.HTTP + this.podUrl | ||
164 | baseUrlWs = constants.REMOTE_SCHEME.WS + this.podUrl | ||
165 | } | ||
166 | |||
167 | const xs = baseUrlHttp + constants.STATIC_PATHS.TORRENTS + this.getTorrentName() | ||
168 | const announce = baseUrlWs + '/tracker/socket' | ||
169 | const urlList = [ baseUrlHttp + constants.STATIC_PATHS.WEBSEED + this.getVideoFilename() ] | ||
170 | |||
171 | const magnetHash = { | ||
172 | xs, | ||
173 | announce, | ||
174 | urlList, | ||
175 | infoHash: this.magnet.infoHash, | ||
176 | name: this.name | ||
177 | } | ||
178 | |||
179 | return magnetUtil.encode(magnetHash) | ||
155 | } | 180 | } |
156 | 181 | ||
157 | function getJPEGName () { | 182 | function getVideoFilename () { |
183 | if (this.isOwned()) return this._id + this.extname | ||
184 | |||
185 | return this.remoteId + this.extname | ||
186 | } | ||
187 | |||
188 | function getThumbnailName () { | ||
189 | // We always have a copy of the thumbnail | ||
158 | return this._id + '.jpg' | 190 | return this._id + '.jpg' |
159 | } | 191 | } |
160 | 192 | ||
193 | function getPreviewName () { | ||
194 | const extension = '.jpg' | ||
195 | |||
196 | if (this.isOwned()) return this._id + extension | ||
197 | |||
198 | return this.remoteId + extension | ||
199 | } | ||
200 | |||
161 | function getTorrentName () { | 201 | function getTorrentName () { |
162 | return this._id + '.torrent' | 202 | const extension = '.torrent' |
203 | |||
204 | if (this.isOwned()) return this._id + extension | ||
205 | |||
206 | return this.remoteId + extension | ||
163 | } | 207 | } |
164 | 208 | ||
165 | function isOwned () { | 209 | function isOwned () { |
@@ -171,13 +215,13 @@ function toFormatedJSON () { | |||
171 | id: this._id, | 215 | id: this._id, |
172 | name: this.name, | 216 | name: this.name, |
173 | description: this.description, | 217 | description: this.description, |
174 | podUrl: this.podUrl.replace(/^https?:\/\//, ''), | 218 | podUrl: this.podUrl, |
175 | isLocal: this.isOwned(), | 219 | isLocal: this.isOwned(), |
176 | magnetUri: this.magnetUri, | 220 | magnetUri: this.generateMagnetUri(), |
177 | author: this.author, | 221 | author: this.author, |
178 | duration: this.duration, | 222 | duration: this.duration, |
179 | tags: this.tags, | 223 | tags: this.tags, |
180 | thumbnailPath: constants.STATIC_PATHS.THUMBNAILS + '/' + this.getJPEGName(), | 224 | thumbnailPath: constants.STATIC_PATHS.THUMBNAILS + '/' + this.getThumbnailName(), |
181 | createdDate: this.createdDate | 225 | createdDate: this.createdDate |
182 | } | 226 | } |
183 | 227 | ||
@@ -188,7 +232,7 @@ function toRemoteJSON (callback) { | |||
188 | const self = this | 232 | const self = this |
189 | 233 | ||
190 | // Convert thumbnail to base64 | 234 | // Convert thumbnail to base64 |
191 | const thumbnailPath = pathUtils.join(constants.CONFIG.STORAGE.THUMBNAILS_DIR, this.getJPEGName()) | 235 | const thumbnailPath = pathUtils.join(constants.CONFIG.STORAGE.THUMBNAILS_DIR, this.getThumbnailName()) |
192 | fs.readFile(thumbnailPath, function (err, thumbnailData) { | 236 | fs.readFile(thumbnailPath, function (err, thumbnailData) { |
193 | if (err) { | 237 | if (err) { |
194 | logger.error('Cannot read the thumbnail of the video') | 238 | logger.error('Cannot read the thumbnail of the video') |
@@ -198,7 +242,7 @@ function toRemoteJSON (callback) { | |||
198 | const remoteVideo = { | 242 | const remoteVideo = { |
199 | name: self.name, | 243 | name: self.name, |
200 | description: self.description, | 244 | description: self.description, |
201 | magnetUri: self.magnetUri, | 245 | magnet: self.magnet, |
202 | remoteId: self._id, | 246 | remoteId: self._id, |
203 | author: self.author, | 247 | author: self.author, |
204 | duration: self.duration, | 248 | duration: self.duration, |
@@ -267,11 +311,11 @@ function search (value, field, start, count, sort, callback) { | |||
267 | // --------------------------------------------------------------------------- | 311 | // --------------------------------------------------------------------------- |
268 | 312 | ||
269 | function removeThumbnail (video, callback) { | 313 | function removeThumbnail (video, callback) { |
270 | fs.unlink(constants.CONFIG.STORAGE.THUMBNAILS_DIR + video.getJPEGName(), callback) | 314 | fs.unlink(constants.CONFIG.STORAGE.THUMBNAILS_DIR + video.getThumbnailName(), callback) |
271 | } | 315 | } |
272 | 316 | ||
273 | function removeFile (video, callback) { | 317 | function removeFile (video, callback) { |
274 | fs.unlink(constants.CONFIG.STORAGE.VIDEOS_DIR + video.getFilename(), callback) | 318 | fs.unlink(constants.CONFIG.STORAGE.VIDEOS_DIR + video.getVideoFilename(), callback) |
275 | } | 319 | } |
276 | 320 | ||
277 | function removeTorrent (video, callback) { | 321 | function removeTorrent (video, callback) { |
@@ -280,22 +324,21 @@ function removeTorrent (video, callback) { | |||
280 | 324 | ||
281 | function removePreview (video, callback) { | 325 | function removePreview (video, callback) { |
282 | // Same name than video thumnail | 326 | // Same name than video thumnail |
283 | // TODO: refractoring | 327 | fs.unlink(constants.CONFIG.STORAGE.PREVIEWS_DIR + video.getPreviewName(), callback) |
284 | fs.unlink(constants.CONFIG.STORAGE.PREVIEWS_DIR + video.getJPEGName(), callback) | ||
285 | } | 328 | } |
286 | 329 | ||
287 | function createPreview (video, videoPath, callback) { | 330 | function createPreview (video, videoPath, callback) { |
288 | generateImage(video, videoPath, constants.CONFIG.STORAGE.PREVIEWS_DIR, callback) | 331 | generateImage(video, videoPath, constants.CONFIG.STORAGE.PREVIEWS_DIR, video.getPreviewName(), callback) |
289 | } | 332 | } |
290 | 333 | ||
291 | function createThumbnail (video, videoPath, callback) { | 334 | function createThumbnail (video, videoPath, callback) { |
292 | generateImage(video, videoPath, constants.CONFIG.STORAGE.THUMBNAILS_DIR, constants.THUMBNAILS_SIZE, callback) | 335 | generateImage(video, videoPath, constants.CONFIG.STORAGE.THUMBNAILS_DIR, video.getThumbnailName(), constants.THUMBNAILS_SIZE, callback) |
293 | } | 336 | } |
294 | 337 | ||
295 | function generateThumbnailFromBase64 (video, thumbnailData, callback) { | 338 | function generateThumbnailFromBase64 (video, thumbnailData, callback) { |
296 | // Creating the thumbnail for this remote video) | 339 | // Creating the thumbnail for this remote video) |
297 | 340 | ||
298 | const thumbnailName = video.getJPEGName() | 341 | const thumbnailName = video.getThumbnailName() |
299 | const thumbnailPath = constants.CONFIG.STORAGE.THUMBNAILS_DIR + thumbnailName | 342 | const thumbnailPath = constants.CONFIG.STORAGE.THUMBNAILS_DIR + thumbnailName |
300 | fs.writeFile(thumbnailPath, thumbnailData, { encoding: 'base64' }, function (err) { | 343 | fs.writeFile(thumbnailPath, thumbnailData, { encoding: 'base64' }, function (err) { |
301 | if (err) return callback(err) | 344 | if (err) return callback(err) |
@@ -304,10 +347,9 @@ function generateThumbnailFromBase64 (video, thumbnailData, callback) { | |||
304 | }) | 347 | }) |
305 | } | 348 | } |
306 | 349 | ||
307 | function generateImage (video, videoPath, folder, size, callback) { | 350 | function generateImage (video, videoPath, folder, imageName, size, callback) { |
308 | const filename = video.getJPEGName() | ||
309 | const options = { | 351 | const options = { |
310 | filename, | 352 | filename: imageName, |
311 | count: 1, | 353 | count: 1, |
312 | folder | 354 | folder |
313 | } | 355 | } |
@@ -321,7 +363,7 @@ function generateImage (video, videoPath, folder, size, callback) { | |||
321 | ffmpeg(videoPath) | 363 | ffmpeg(videoPath) |
322 | .on('error', callback) | 364 | .on('error', callback) |
323 | .on('end', function () { | 365 | .on('end', function () { |
324 | callback(null, filename) | 366 | callback(null, imageName) |
325 | }) | 367 | }) |
326 | .thumbnail(options) | 368 | .thumbnail(options) |
327 | } | 369 | } |