aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/models/video.js
diff options
context:
space:
mode:
Diffstat (limited to 'server/models/video.js')
-rw-r--r--server/models/video.js97
1 files changed, 57 insertions, 40 deletions
diff --git a/server/models/video.js b/server/models/video.js
index 8ef07c9e6..0023a24e1 100644
--- a/server/models/video.js
+++ b/server/models/video.js
@@ -4,6 +4,7 @@ const createTorrent = require('create-torrent')
4const ffmpeg = require('fluent-ffmpeg') 4const ffmpeg = require('fluent-ffmpeg')
5const fs = require('fs') 5const fs = require('fs')
6const magnetUtil = require('magnet-uri') 6const magnetUtil = require('magnet-uri')
7const map = require('lodash/map')
7const parallel = require('async/parallel') 8const parallel = require('async/parallel')
8const parseTorrent = require('parse-torrent') 9const parseTorrent = require('parse-torrent')
9const pathUtils = require('path') 10const pathUtils = require('path')
@@ -41,9 +42,6 @@ module.exports = function (sequelize, DataTypes) {
41 }, 42 },
42 duration: { 43 duration: {
43 type: DataTypes.INTEGER 44 type: DataTypes.INTEGER
44 },
45 tags: {
46 type: DataTypes.ARRAY(DataTypes.STRING)
47 } 45 }
48 }, 46 },
49 { 47 {
@@ -54,12 +52,12 @@ module.exports = function (sequelize, DataTypes) {
54 getDurationFromFile, 52 getDurationFromFile,
55 listForApi, 53 listForApi,
56 listByHostAndRemoteId, 54 listByHostAndRemoteId,
57 listOwnedAndPopulateAuthor, 55 listOwnedAndPopulateAuthorAndTags,
58 listOwnedByAuthor, 56 listOwnedByAuthor,
59 load, 57 load,
60 loadAndPopulateAuthor, 58 loadAndPopulateAuthor,
61 loadAndPopulateAuthorAndPod, 59 loadAndPopulateAuthorAndPodAndTags,
62 searchAndPopulateAuthorAndPod 60 searchAndPopulateAuthorAndPodAndTags
63 }, 61 },
64 instanceMethods: { 62 instanceMethods: {
65 generateMagnetUri, 63 generateMagnetUri,
@@ -170,6 +168,12 @@ function associate (models) {
170 }, 168 },
171 onDelete: 'cascade' 169 onDelete: 'cascade'
172 }) 170 })
171
172 this.belongsToMany(models.Tag, {
173 foreignKey: 'videoId',
174 through: models.VideoTag,
175 onDelete: 'cascade'
176 })
173} 177}
174 178
175function generateMagnetUri () { 179function generateMagnetUri () {
@@ -248,7 +252,7 @@ function toFormatedJSON () {
248 magnetUri: this.generateMagnetUri(), 252 magnetUri: this.generateMagnetUri(),
249 author: this.Author.name, 253 author: this.Author.name,
250 duration: this.duration, 254 duration: this.duration,
251 tags: this.tags, 255 tags: map(this.Tags, 'name'),
252 thumbnailPath: constants.STATIC_PATHS.THUMBNAILS + '/' + this.getThumbnailName(), 256 thumbnailPath: constants.STATIC_PATHS.THUMBNAILS + '/' + this.getThumbnailName(),
253 createdAt: this.createdAt 257 createdAt: this.createdAt
254 } 258 }
@@ -275,7 +279,7 @@ function toRemoteJSON (callback) {
275 author: self.Author.name, 279 author: self.Author.name,
276 duration: self.duration, 280 duration: self.duration,
277 thumbnailBase64: new Buffer(thumbnailData).toString('base64'), 281 thumbnailBase64: new Buffer(thumbnailData).toString('base64'),
278 tags: self.tags, 282 tags: map(self.Tags, 'name'),
279 createdAt: self.createdAt, 283 createdAt: self.createdAt,
280 extname: self.extname 284 extname: self.extname
281 } 285 }
@@ -310,12 +314,15 @@ function listForApi (start, count, sort, callback) {
310 const query = { 314 const query = {
311 offset: start, 315 offset: start,
312 limit: count, 316 limit: count,
317 distinct: true, // For the count, a video can have many tags
313 order: [ modelUtils.getSort(sort) ], 318 order: [ modelUtils.getSort(sort) ],
314 include: [ 319 include: [
315 { 320 {
316 model: this.sequelize.models.Author, 321 model: this.sequelize.models.Author,
317 include: [ this.sequelize.models.Pod ] 322 include: [ { model: this.sequelize.models.Pod, required: false } ]
318 } 323 },
324
325 this.sequelize.models.Tag
319 ] 326 ]
320 } 327 }
321 328
@@ -337,6 +344,7 @@ function listByHostAndRemoteId (fromHost, remoteId, callback) {
337 include: [ 344 include: [
338 { 345 {
339 model: this.sequelize.models.Pod, 346 model: this.sequelize.models.Pod,
347 required: true,
340 where: { 348 where: {
341 host: fromHost 349 host: fromHost
342 } 350 }
@@ -349,13 +357,13 @@ function listByHostAndRemoteId (fromHost, remoteId, callback) {
349 return this.findAll(query).asCallback(callback) 357 return this.findAll(query).asCallback(callback)
350} 358}
351 359
352function listOwnedAndPopulateAuthor (callback) { 360function listOwnedAndPopulateAuthorAndTags (callback) {
353 // If remoteId is null this is *our* video 361 // If remoteId is null this is *our* video
354 const query = { 362 const query = {
355 where: { 363 where: {
356 remoteId: null 364 remoteId: null
357 }, 365 },
358 include: [ this.sequelize.models.Author ] 366 include: [ this.sequelize.models.Author, this.sequelize.models.Tag ]
359 } 367 }
360 368
361 return this.findAll(query).asCallback(callback) 369 return this.findAll(query).asCallback(callback)
@@ -391,23 +399,26 @@ function loadAndPopulateAuthor (id, callback) {
391 return this.findById(id, options).asCallback(callback) 399 return this.findById(id, options).asCallback(callback)
392} 400}
393 401
394function loadAndPopulateAuthorAndPod (id, callback) { 402function loadAndPopulateAuthorAndPodAndTags (id, callback) {
395 const options = { 403 const options = {
396 include: [ 404 include: [
397 { 405 {
398 model: this.sequelize.models.Author, 406 model: this.sequelize.models.Author,
399 include: [ this.sequelize.models.Pod ] 407 include: [ { model: this.sequelize.models.Pod, required: false } ]
400 } 408 },
409 this.sequelize.models.Tag
401 ] 410 ]
402 } 411 }
403 412
404 return this.findById(id, options).asCallback(callback) 413 return this.findById(id, options).asCallback(callback)
405} 414}
406 415
407function searchAndPopulateAuthorAndPod (value, field, start, count, sort, callback) { 416function searchAndPopulateAuthorAndPodAndTags (value, field, start, count, sort, callback) {
408 const podInclude = { 417 const podInclude = {
409 model: this.sequelize.models.Pod 418 model: this.sequelize.models.Pod,
419 required: false
410 } 420 }
421
411 const authorInclude = { 422 const authorInclude = {
412 model: this.sequelize.models.Author, 423 model: this.sequelize.models.Author,
413 include: [ 424 include: [
@@ -415,55 +426,61 @@ function searchAndPopulateAuthorAndPod (value, field, start, count, sort, callba
415 ] 426 ]
416 } 427 }
417 428
429 const tagInclude = {
430 model: this.sequelize.models.Tag
431 }
432
418 const query = { 433 const query = {
419 where: {}, 434 where: {},
420 include: [
421 authorInclude
422 ],
423 offset: start, 435 offset: start,
424 limit: count, 436 limit: count,
437 distinct: true, // For the count, a video can have many tags
425 order: [ modelUtils.getSort(sort) ] 438 order: [ modelUtils.getSort(sort) ]
426 } 439 }
427 440
428 // TODO: include our pod for podHost searches (we are not stored in the database)
429 // Make an exact search with the magnet 441 // Make an exact search with the magnet
430 if (field === 'magnetUri') { 442 if (field === 'magnetUri') {
431 const infoHash = magnetUtil.decode(value).infoHash 443 const infoHash = magnetUtil.decode(value).infoHash
432 query.where.infoHash = infoHash 444 query.where.infoHash = infoHash
433 } else if (field === 'tags') { 445 } else if (field === 'tags') {
434 query.where[field] = value 446 const escapedValue = this.sequelize.escape('%' + value + '%')
435 } else if (field === 'host') { 447 query.where = {
436 const whereQuery = { 448 id: {
437 '$Author.Pod.host$': { 449 $in: this.sequelize.literal(
438 $like: '%' + value + '%' 450 '(SELECT "VideoTags"."videoId" FROM "Tags" INNER JOIN "VideoTags" ON "Tags"."id" = "VideoTags"."tagId" WHERE name LIKE ' + escapedValue + ')'
451 )
439 } 452 }
440 } 453 }
441 454 } else if (field === 'host') {
442 // Include our pod? (not stored in the database) 455 // FIXME: Include our pod? (not stored in the database)
443 if (constants.CONFIG.WEBSERVER.HOST.indexOf(value) !== -1) { 456 podInclude.where = {
444 query.where = { 457 host: {
445 $or: [ 458 $like: '%' + value + '%'
446 whereQuery,
447 {
448 remoteId: null
449 }
450 ]
451 } 459 }
452 } else {
453 query.where = whereQuery
454 } 460 }
461 podInclude.required = true
455 } else if (field === 'author') { 462 } else if (field === 'author') {
456 query.where = { 463 authorInclude.where = {
457 '$Author.name$': { 464 name: {
458 $like: '%' + value + '%' 465 $like: '%' + value + '%'
459 } 466 }
460 } 467 }
468
469 // authorInclude.or = true
461 } else { 470 } else {
462 query.where[field] = { 471 query.where[field] = {
463 $like: '%' + value + '%' 472 $like: '%' + value + '%'
464 } 473 }
465 } 474 }
466 475
476 query.include = [
477 authorInclude, tagInclude
478 ]
479
480 if (tagInclude.where) {
481 // query.include.push([ this.sequelize.models.Tag ])
482 }
483
467 return this.findAndCountAll(query).asCallback(function (err, result) { 484 return this.findAndCountAll(query).asCallback(function (err, result) {
468 if (err) return callback(err) 485 if (err) return callback(err)
469 486