aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/models/video.ts
diff options
context:
space:
mode:
Diffstat (limited to 'server/models/video.ts')
-rw-r--r--server/models/video.ts379
1 files changed, 210 insertions, 169 deletions
diff --git a/server/models/video.ts b/server/models/video.ts
index 1e29f1355..9284dfeba 100644
--- a/server/models/video.ts
+++ b/server/models/video.ts
@@ -8,8 +8,9 @@ import { map, values } from 'lodash'
8import { parallel, series } from 'async' 8import { parallel, series } from 'async'
9import parseTorrent = require('parse-torrent') 9import parseTorrent = require('parse-torrent')
10import { join } from 'path' 10import { join } from 'path'
11import * as Sequelize from 'sequelize'
11 12
12const db = require('../initializers/database') 13import { database as db } from '../initializers/database'
13import { 14import {
14 logger, 15 logger,
15 isVideoNameValid, 16 isVideoNameValid,
@@ -32,12 +33,42 @@ import {
32 THUMBNAILS_SIZE 33 THUMBNAILS_SIZE
33} from '../initializers' 34} from '../initializers'
34import { JobScheduler, removeVideoToFriends } from '../lib' 35import { JobScheduler, removeVideoToFriends } from '../lib'
35import { getSort } from './utils'
36 36
37// --------------------------------------------------------------------------- 37import { addMethodsToModel, getSort } from './utils'
38 38import {
39module.exports = function (sequelize, DataTypes) { 39 VideoClass,
40 const Video = sequelize.define('Video', 40 VideoInstance,
41 VideoAttributes,
42
43 VideoMethods
44} from './video-interface'
45
46let Video: Sequelize.Model<VideoInstance, VideoAttributes>
47let generateMagnetUri: VideoMethods.GenerateMagnetUri
48let getVideoFilename: VideoMethods.GetVideoFilename
49let getThumbnailName: VideoMethods.GetThumbnailName
50let getPreviewName: VideoMethods.GetPreviewName
51let getTorrentName: VideoMethods.GetTorrentName
52let isOwned: VideoMethods.IsOwned
53let toFormatedJSON: VideoMethods.ToFormatedJSON
54let toAddRemoteJSON: VideoMethods.ToAddRemoteJSON
55let toUpdateRemoteJSON: VideoMethods.ToUpdateRemoteJSON
56let transcodeVideofile: VideoMethods.TranscodeVideofile
57
58let generateThumbnailFromData: VideoMethods.GenerateThumbnailFromData
59let getDurationFromFile: VideoMethods.GetDurationFromFile
60let list: VideoMethods.List
61let listForApi: VideoMethods.ListForApi
62let loadByHostAndRemoteId: VideoMethods.LoadByHostAndRemoteId
63let listOwnedAndPopulateAuthorAndTags: VideoMethods.ListOwnedAndPopulateAuthorAndTags
64let listOwnedByAuthor: VideoMethods.ListOwnedByAuthor
65let load: VideoMethods.Load
66let loadAndPopulateAuthor: VideoMethods.LoadAndPopulateAuthor
67let loadAndPopulateAuthorAndPodAndTags: VideoMethods.LoadAndPopulateAuthorAndPodAndTags
68let searchAndPopulateAuthorAndPodAndTags: VideoMethods.SearchAndPopulateAuthorAndPodAndTags
69
70export default function (sequelize, DataTypes) {
71 Video = sequelize.define('Video',
41 { 72 {
42 id: { 73 id: {
43 type: DataTypes.UUID, 74 type: DataTypes.UUID,
@@ -194,34 +225,6 @@ module.exports = function (sequelize, DataTypes) {
194 fields: [ 'likes' ] 225 fields: [ 'likes' ]
195 } 226 }
196 ], 227 ],
197 classMethods: {
198 associate,
199
200 generateThumbnailFromData,
201 getDurationFromFile,
202 list,
203 listForApi,
204 listOwnedAndPopulateAuthorAndTags,
205 listOwnedByAuthor,
206 load,
207 loadByHostAndRemoteId,
208 loadAndPopulateAuthor,
209 loadAndPopulateAuthorAndPodAndTags,
210 searchAndPopulateAuthorAndPodAndTags
211 },
212 instanceMethods: {
213 generateMagnetUri,
214 getVideoFilename,
215 getThumbnailName,
216 getPreviewName,
217 getTorrentName,
218 isOwned,
219 toFormatedJSON,
220 toAddRemoteJSON,
221 toUpdateRemoteJSON,
222 transcodeVideofile,
223 removeFromBlacklist
224 },
225 hooks: { 228 hooks: {
226 beforeValidate, 229 beforeValidate,
227 beforeCreate, 230 beforeCreate,
@@ -230,99 +233,139 @@ module.exports = function (sequelize, DataTypes) {
230 } 233 }
231 ) 234 )
232 235
236 const classMethods = [
237 associate,
238
239 generateThumbnailFromData,
240 getDurationFromFile,
241 list,
242 listForApi,
243 listOwnedAndPopulateAuthorAndTags,
244 listOwnedByAuthor,
245 load,
246 loadByHostAndRemoteId,
247 loadAndPopulateAuthor,
248 loadAndPopulateAuthorAndPodAndTags,
249 searchAndPopulateAuthorAndPodAndTags
250 ]
251 const instanceMethods = [
252 generateMagnetUri,
253 getVideoFilename,
254 getThumbnailName,
255 getPreviewName,
256 getTorrentName,
257 isOwned,
258 toFormatedJSON,
259 toAddRemoteJSON,
260 toUpdateRemoteJSON,
261 transcodeVideofile,
262 removeFromBlacklist
263 ]
264 addMethodsToModel(Video, classMethods, instanceMethods)
265
233 return Video 266 return Video
234} 267}
235 268
236function beforeValidate (video, options, next) { 269function beforeValidate (video, options) {
237 // Put a fake infoHash if it does not exists yet 270 // Put a fake infoHash if it does not exists yet
238 if (video.isOwned() && !video.infoHash) { 271 if (video.isOwned() && !video.infoHash) {
239 // 40 hexa length 272 // 40 hexa length
240 video.infoHash = '0123456789abcdef0123456789abcdef01234567' 273 video.infoHash = '0123456789abcdef0123456789abcdef01234567'
241 } 274 }
242
243 return next(null)
244} 275}
245 276
246function beforeCreate (video, options, next) { 277function beforeCreate (video, options) {
247 const tasks = [] 278 return new Promise(function (resolve, reject) {
248 279 const tasks = []
249 if (video.isOwned()) {
250 const videoPath = join(CONFIG.STORAGE.VIDEOS_DIR, video.getVideoFilename())
251
252 tasks.push(
253 function createVideoTorrent (callback) {
254 createTorrentFromVideo(video, videoPath, callback)
255 },
256
257 function createVideoThumbnail (callback) {
258 createThumbnail(video, videoPath, callback)
259 },
260 280
261 function createVideoPreview (callback) { 281 if (video.isOwned()) {
262 createPreview(video, videoPath, callback) 282 const videoPath = join(CONFIG.STORAGE.VIDEOS_DIR, video.getVideoFilename())
263 }
264 )
265 283
266 if (CONFIG.TRANSCODING.ENABLED === true) {
267 tasks.push( 284 tasks.push(
268 function createVideoTranscoderJob (callback) { 285 function createVideoTorrent (callback) {
269 const dataInput = { 286 createTorrentFromVideo(video, videoPath, callback)
270 id: video.id 287 },
271 } 288
289 function createVideoThumbnail (callback) {
290 createThumbnail(video, videoPath, callback)
291 },
272 292
273 JobScheduler.Instance.createJob(options.transaction, 'videoTranscoder', dataInput, callback) 293 function createVideoPreview (callback) {
294 createPreview(video, videoPath, callback)
274 } 295 }
275 ) 296 )
276 }
277 297
278 return parallel(tasks, next) 298 if (CONFIG.TRANSCODING.ENABLED === true) {
279 } 299 tasks.push(
300 function createVideoTranscoderJob (callback) {
301 const dataInput = {
302 id: video.id
303 }
280 304
281 return next() 305 JobScheduler.Instance.createJob(options.transaction, 'videoTranscoder', dataInput, callback)
282} 306 }
307 )
308 }
283 309
284function afterDestroy (video, options, next) { 310 return parallel(tasks, function (err) {
285 const tasks = [] 311 if (err) return reject(err)
286 312
287 tasks.push( 313 return resolve()
288 function (callback) { 314 })
289 removeThumbnail(video, callback)
290 } 315 }
291 )
292 316
293 if (video.isOwned()) { 317 return resolve()
318 })
319}
320
321function afterDestroy (video, options) {
322 return new Promise(function (resolve, reject) {
323 const tasks = []
324
294 tasks.push( 325 tasks.push(
295 function removeVideoFile (callback) { 326 function (callback) {
296 removeFile(video, callback) 327 removeThumbnail(video, callback)
297 }, 328 }
329 )
298 330
299 function removeVideoTorrent (callback) { 331 if (video.isOwned()) {
300 removeTorrent(video, callback) 332 tasks.push(
301 }, 333 function removeVideoFile (callback) {
334 removeFile(video, callback)
335 },
302 336
303 function removeVideoPreview (callback) { 337 function removeVideoTorrent (callback) {
304 removePreview(video, callback) 338 removeTorrent(video, callback)
305 }, 339 },
306 340
307 function removeVideoToFriends (callback) { 341 function removeVideoPreview (callback) {
308 const params = { 342 removePreview(video, callback)
309 remoteId: video.id 343 },
310 }
311 344
312 removeVideoToFriends(params) 345 function notifyFriends (callback) {
346 const params = {
347 remoteId: video.id
348 }
313 349
314 return callback() 350 removeVideoToFriends(params)
315 }
316 )
317 }
318 351
319 parallel(tasks, next) 352 return callback()
353 }
354 )
355 }
356
357 parallel(tasks, function (err) {
358 if (err) return reject(err)
359
360 return resolve()
361 })
362 })
320} 363}
321 364
322// ------------------------------ METHODS ------------------------------ 365// ------------------------------ METHODS ------------------------------
323 366
324function associate (models) { 367function associate (models) {
325 this.belongsTo(models.Author, { 368 Video.belongsTo(models.Author, {
326 foreignKey: { 369 foreignKey: {
327 name: 'authorId', 370 name: 'authorId',
328 allowNull: false 371 allowNull: false
@@ -330,13 +373,13 @@ function associate (models) {
330 onDelete: 'cascade' 373 onDelete: 'cascade'
331 }) 374 })
332 375
333 this.belongsToMany(models.Tag, { 376 Video.belongsToMany(models.Tag, {
334 foreignKey: 'videoId', 377 foreignKey: 'videoId',
335 through: models.VideoTag, 378 through: models.VideoTag,
336 onDelete: 'cascade' 379 onDelete: 'cascade'
337 }) 380 })
338 381
339 this.hasMany(models.VideoAbuse, { 382 Video.hasMany(models.VideoAbuse, {
340 foreignKey: { 383 foreignKey: {
341 name: 'videoId', 384 name: 'videoId',
342 allowNull: false 385 allowNull: false
@@ -345,7 +388,7 @@ function associate (models) {
345 }) 388 })
346} 389}
347 390
348function generateMagnetUri () { 391generateMagnetUri = function () {
349 let baseUrlHttp 392 let baseUrlHttp
350 let baseUrlWs 393 let baseUrlWs
351 394
@@ -372,18 +415,18 @@ function generateMagnetUri () {
372 return magnetUtil.encode(magnetHash) 415 return magnetUtil.encode(magnetHash)
373} 416}
374 417
375function getVideoFilename () { 418getVideoFilename = function () {
376 if (this.isOwned()) return this.id + this.extname 419 if (this.isOwned()) return this.id + this.extname
377 420
378 return this.remoteId + this.extname 421 return this.remoteId + this.extname
379} 422}
380 423
381function getThumbnailName () { 424getThumbnailName = function () {
382 // We always have a copy of the thumbnail 425 // We always have a copy of the thumbnail
383 return this.id + '.jpg' 426 return this.id + '.jpg'
384} 427}
385 428
386function getPreviewName () { 429getPreviewName = function () {
387 const extension = '.jpg' 430 const extension = '.jpg'
388 431
389 if (this.isOwned()) return this.id + extension 432 if (this.isOwned()) return this.id + extension
@@ -391,7 +434,7 @@ function getPreviewName () {
391 return this.remoteId + extension 434 return this.remoteId + extension
392} 435}
393 436
394function getTorrentName () { 437getTorrentName = function () {
395 const extension = '.torrent' 438 const extension = '.torrent'
396 439
397 if (this.isOwned()) return this.id + extension 440 if (this.isOwned()) return this.id + extension
@@ -399,11 +442,11 @@ function getTorrentName () {
399 return this.remoteId + extension 442 return this.remoteId + extension
400} 443}
401 444
402function isOwned () { 445isOwned = function () {
403 return this.remoteId === null 446 return this.remoteId === null
404} 447}
405 448
406function toFormatedJSON () { 449toFormatedJSON = function () {
407 let podHost 450 let podHost
408 451
409 if (this.Author.Pod) { 452 if (this.Author.Pod) {
@@ -453,43 +496,41 @@ function toFormatedJSON () {
453 return json 496 return json
454} 497}
455 498
456function toAddRemoteJSON (callback) { 499toAddRemoteJSON = function (callback) {
457 const self = this
458
459 // Get thumbnail data to send to the other pod 500 // Get thumbnail data to send to the other pod
460 const thumbnailPath = join(CONFIG.STORAGE.THUMBNAILS_DIR, this.getThumbnailName()) 501 const thumbnailPath = join(CONFIG.STORAGE.THUMBNAILS_DIR, this.getThumbnailName())
461 fs.readFile(thumbnailPath, function (err, thumbnailData) { 502 fs.readFile(thumbnailPath, (err, thumbnailData) => {
462 if (err) { 503 if (err) {
463 logger.error('Cannot read the thumbnail of the video') 504 logger.error('Cannot read the thumbnail of the video')
464 return callback(err) 505 return callback(err)
465 } 506 }
466 507
467 const remoteVideo = { 508 const remoteVideo = {
468 name: self.name, 509 name: this.name,
469 category: self.category, 510 category: this.category,
470 licence: self.licence, 511 licence: this.licence,
471 language: self.language, 512 language: this.language,
472 nsfw: self.nsfw, 513 nsfw: this.nsfw,
473 description: self.description, 514 description: this.description,
474 infoHash: self.infoHash, 515 infoHash: this.infoHash,
475 remoteId: self.id, 516 remoteId: this.id,
476 author: self.Author.name, 517 author: this.Author.name,
477 duration: self.duration, 518 duration: this.duration,
478 thumbnailData: thumbnailData.toString('binary'), 519 thumbnailData: thumbnailData.toString('binary'),
479 tags: map(self.Tags, 'name'), 520 tags: map(this.Tags, 'name'),
480 createdAt: self.createdAt, 521 createdAt: this.createdAt,
481 updatedAt: self.updatedAt, 522 updatedAt: this.updatedAt,
482 extname: self.extname, 523 extname: this.extname,
483 views: self.views, 524 views: this.views,
484 likes: self.likes, 525 likes: this.likes,
485 dislikes: self.dislikes 526 dislikes: this.dislikes
486 } 527 }
487 528
488 return callback(null, remoteVideo) 529 return callback(null, remoteVideo)
489 }) 530 })
490} 531}
491 532
492function toUpdateRemoteJSON (callback) { 533toUpdateRemoteJSON = function (callback) {
493 const json = { 534 const json = {
494 name: this.name, 535 name: this.name,
495 category: this.category, 536 category: this.category,
@@ -513,7 +554,7 @@ function toUpdateRemoteJSON (callback) {
513 return json 554 return json
514} 555}
515 556
516function transcodeVideofile (finalCallback) { 557transcodeVideofile = function (finalCallback) {
517 const video = this 558 const video = this
518 559
519 const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR 560 const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR
@@ -568,7 +609,7 @@ function transcodeVideofile (finalCallback) {
568 609
569// ------------------------------ STATICS ------------------------------ 610// ------------------------------ STATICS ------------------------------
570 611
571function generateThumbnailFromData (video, thumbnailData, callback) { 612generateThumbnailFromData = function (video, thumbnailData, callback) {
572 // Creating the thumbnail for a remote video 613 // Creating the thumbnail for a remote video
573 614
574 const thumbnailName = video.getThumbnailName() 615 const thumbnailName = video.getThumbnailName()
@@ -580,7 +621,7 @@ function generateThumbnailFromData (video, thumbnailData, callback) {
580 }) 621 })
581} 622}
582 623
583function getDurationFromFile (videoPath, callback) { 624getDurationFromFile = function (videoPath, callback) {
584 ffmpeg.ffprobe(videoPath, function (err, metadata) { 625 ffmpeg.ffprobe(videoPath, function (err, metadata) {
585 if (err) return callback(err) 626 if (err) return callback(err)
586 627
@@ -588,46 +629,46 @@ function getDurationFromFile (videoPath, callback) {
588 }) 629 })
589} 630}
590 631
591function list (callback) { 632list = function (callback) {
592 return this.findAll().asCallback(callback) 633 return Video.findAll().asCallback(callback)
593} 634}
594 635
595function listForApi (start, count, sort, callback) { 636listForApi = function (start, count, sort, callback) {
596 // Exclude Blakclisted videos from the list 637 // Exclude Blakclisted videos from the list
597 const query = { 638 const query = {
639 distinct: true,
598 offset: start, 640 offset: start,
599 limit: count, 641 limit: count,
600 distinct: true, // For the count, a video can have many tags 642 order: [ getSort(sort), [ Video['sequelize'].models.Tag, 'name', 'ASC' ] ],
601 order: [ getSort(sort), [ this.sequelize.models.Tag, 'name', 'ASC' ] ],
602 include: [ 643 include: [
603 { 644 {
604 model: this.sequelize.models.Author, 645 model: Video['sequelize'].models.Author,
605 include: [ { model: this.sequelize.models.Pod, required: false } ] 646 include: [ { model: Video['sequelize'].models.Pod, required: false } ]
606 }, 647 },
607 648
608 this.sequelize.models.Tag 649 Video['sequelize'].models.Tag
609 ], 650 ],
610 where: createBaseVideosWhere.call(this) 651 where: createBaseVideosWhere()
611 } 652 }
612 653
613 return this.findAndCountAll(query).asCallback(function (err, result) { 654 return Video.findAndCountAll(query).asCallback(function (err, result) {
614 if (err) return callback(err) 655 if (err) return callback(err)
615 656
616 return callback(null, result.rows, result.count) 657 return callback(null, result.rows, result.count)
617 }) 658 })
618} 659}
619 660
620function loadByHostAndRemoteId (fromHost, remoteId, callback) { 661loadByHostAndRemoteId = function (fromHost, remoteId, callback) {
621 const query = { 662 const query = {
622 where: { 663 where: {
623 remoteId: remoteId 664 remoteId: remoteId
624 }, 665 },
625 include: [ 666 include: [
626 { 667 {
627 model: this.sequelize.models.Author, 668 model: Video['sequelize'].models.Author,
628 include: [ 669 include: [
629 { 670 {
630 model: this.sequelize.models.Pod, 671 model: Video['sequelize'].models.Pod,
631 required: true, 672 required: true,
632 where: { 673 where: {
633 host: fromHost 674 host: fromHost
@@ -638,29 +679,29 @@ function loadByHostAndRemoteId (fromHost, remoteId, callback) {
638 ] 679 ]
639 } 680 }
640 681
641 return this.findOne(query).asCallback(callback) 682 return Video.findOne(query).asCallback(callback)
642} 683}
643 684
644function listOwnedAndPopulateAuthorAndTags (callback) { 685listOwnedAndPopulateAuthorAndTags = function (callback) {
645 // If remoteId is null this is *our* video 686 // If remoteId is null this is *our* video
646 const query = { 687 const query = {
647 where: { 688 where: {
648 remoteId: null 689 remoteId: null
649 }, 690 },
650 include: [ this.sequelize.models.Author, this.sequelize.models.Tag ] 691 include: [ Video['sequelize'].models.Author, Video['sequelize'].models.Tag ]
651 } 692 }
652 693
653 return this.findAll(query).asCallback(callback) 694 return Video.findAll(query).asCallback(callback)
654} 695}
655 696
656function listOwnedByAuthor (author, callback) { 697listOwnedByAuthor = function (author, callback) {
657 const query = { 698 const query = {
658 where: { 699 where: {
659 remoteId: null 700 remoteId: null
660 }, 701 },
661 include: [ 702 include: [
662 { 703 {
663 model: this.sequelize.models.Author, 704 model: Video['sequelize'].models.Author,
664 where: { 705 where: {
665 name: author 706 name: author
666 } 707 }
@@ -668,58 +709,58 @@ function listOwnedByAuthor (author, callback) {
668 ] 709 ]
669 } 710 }
670 711
671 return this.findAll(query).asCallback(callback) 712 return Video.findAll(query).asCallback(callback)
672} 713}
673 714
674function load (id, callback) { 715load = function (id, callback) {
675 return this.findById(id).asCallback(callback) 716 return Video.findById(id).asCallback(callback)
676} 717}
677 718
678function loadAndPopulateAuthor (id, callback) { 719loadAndPopulateAuthor = function (id, callback) {
679 const options = { 720 const options = {
680 include: [ this.sequelize.models.Author ] 721 include: [ Video['sequelize'].models.Author ]
681 } 722 }
682 723
683 return this.findById(id, options).asCallback(callback) 724 return Video.findById(id, options).asCallback(callback)
684} 725}
685 726
686function loadAndPopulateAuthorAndPodAndTags (id, callback) { 727loadAndPopulateAuthorAndPodAndTags = function (id, callback) {
687 const options = { 728 const options = {
688 include: [ 729 include: [
689 { 730 {
690 model: this.sequelize.models.Author, 731 model: Video['sequelize'].models.Author,
691 include: [ { model: this.sequelize.models.Pod, required: false } ] 732 include: [ { model: Video['sequelize'].models.Pod, required: false } ]
692 }, 733 },
693 this.sequelize.models.Tag 734 Video['sequelize'].models.Tag
694 ] 735 ]
695 } 736 }
696 737
697 return this.findById(id, options).asCallback(callback) 738 return Video.findById(id, options).asCallback(callback)
698} 739}
699 740
700function searchAndPopulateAuthorAndPodAndTags (value, field, start, count, sort, callback) { 741searchAndPopulateAuthorAndPodAndTags = function (value, field, start, count, sort, callback) {
701 const podInclude: any = { 742 const podInclude: any = {
702 model: this.sequelize.models.Pod, 743 model: Video['sequelize'].models.Pod,
703 required: false 744 required: false
704 } 745 }
705 746
706 const authorInclude: any = { 747 const authorInclude: any = {
707 model: this.sequelize.models.Author, 748 model: Video['sequelize'].models.Author,
708 include: [ 749 include: [
709 podInclude 750 podInclude
710 ] 751 ]
711 } 752 }
712 753
713 const tagInclude: any = { 754 const tagInclude: any = {
714 model: this.sequelize.models.Tag 755 model: Video['sequelize'].models.Tag
715 } 756 }
716 757
717 const query: any = { 758 const query: any = {
718 where: createBaseVideosWhere.call(this), 759 distinct: true,
760 where: createBaseVideosWhere(),
719 offset: start, 761 offset: start,
720 limit: count, 762 limit: count,
721 distinct: true, // For the count, a video can have many tags 763 order: [ getSort(sort), [ Video['sequelize'].models.Tag, 'name', 'ASC' ] ]
722 order: [ getSort(sort), [ this.sequelize.models.Tag, 'name', 'ASC' ] ]
723 } 764 }
724 765
725 // Make an exact search with the magnet 766 // Make an exact search with the magnet
@@ -727,8 +768,8 @@ function searchAndPopulateAuthorAndPodAndTags (value, field, start, count, sort,
727 const infoHash = magnetUtil.decode(value).infoHash 768 const infoHash = magnetUtil.decode(value).infoHash
728 query.where.infoHash = infoHash 769 query.where.infoHash = infoHash
729 } else if (field === 'tags') { 770 } else if (field === 'tags') {
730 const escapedValue = this.sequelize.escape('%' + value + '%') 771 const escapedValue = Video['sequelize'].escape('%' + value + '%')
731 query.where.id.$in = this.sequelize.literal( 772 query.where.id.$in = Video['sequelize'].literal(
732 '(SELECT "VideoTags"."videoId" FROM "Tags" INNER JOIN "VideoTags" ON "Tags"."id" = "VideoTags"."tagId" WHERE name LIKE ' + escapedValue + ')' 773 '(SELECT "VideoTags"."videoId" FROM "Tags" INNER JOIN "VideoTags" ON "Tags"."id" = "VideoTags"."tagId" WHERE name LIKE ' + escapedValue + ')'
733 ) 774 )
734 } else if (field === 'host') { 775 } else if (field === 'host') {
@@ -758,10 +799,10 @@ function searchAndPopulateAuthorAndPodAndTags (value, field, start, count, sort,
758 ] 799 ]
759 800
760 if (tagInclude.where) { 801 if (tagInclude.where) {
761 // query.include.push([ this.sequelize.models.Tag ]) 802 // query.include.push([ Video['sequelize'].models.Tag ])
762 } 803 }
763 804
764 return this.findAndCountAll(query).asCallback(function (err, result) { 805 return Video.findAndCountAll(query).asCallback(function (err, result) {
765 if (err) return callback(err) 806 if (err) return callback(err)
766 807
767 return callback(null, result.rows, result.count) 808 return callback(null, result.rows, result.count)
@@ -773,7 +814,7 @@ function searchAndPopulateAuthorAndPodAndTags (value, field, start, count, sort,
773function createBaseVideosWhere () { 814function createBaseVideosWhere () {
774 return { 815 return {
775 id: { 816 id: {
776 $notIn: this.sequelize.literal( 817 $notIn: Video['sequelize'].literal(
777 '(SELECT "BlacklistedVideos"."videoId" FROM "BlacklistedVideos")' 818 '(SELECT "BlacklistedVideos"."videoId" FROM "BlacklistedVideos")'
778 ) 819 )
779 } 820 }