aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/models/video
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2021-07-28 16:40:21 +0200
committerChocobozzz <me@florianbigard.com>2021-07-28 16:40:21 +0200
commitfbd67e7f386504e50f2504cb6386700a58906f16 (patch)
tree1a7143aaea76ce4e195fb9d6214a0cd769c556ea /server/models/video
parent164c8d46cf5c948a28b4ac0e596fad9b83b2c229 (diff)
downloadPeerTube-fbd67e7f386504e50f2504cb6386700a58906f16.tar.gz
PeerTube-fbd67e7f386504e50f2504cb6386700a58906f16.tar.zst
PeerTube-fbd67e7f386504e50f2504cb6386700a58906f16.zip
Add ability to search by uuids/actor names
Diffstat (limited to 'server/models/video')
-rw-r--r--server/models/video/sql/videos-id-list-query-builder.ts10
-rw-r--r--server/models/video/video-channel.ts76
-rw-r--r--server/models/video/video-playlist.ts16
-rw-r--r--server/models/video/video.ts3
4 files changed, 75 insertions, 30 deletions
diff --git a/server/models/video/sql/videos-id-list-query-builder.ts b/server/models/video/sql/videos-id-list-query-builder.ts
index d4260c69c..7625c003d 100644
--- a/server/models/video/sql/videos-id-list-query-builder.ts
+++ b/server/models/video/sql/videos-id-list-query-builder.ts
@@ -35,6 +35,8 @@ export type BuildVideosListQueryOptions = {
35 tagsOneOf?: string[] 35 tagsOneOf?: string[]
36 tagsAllOf?: string[] 36 tagsAllOf?: string[]
37 37
38 uuids?: string[]
39
38 withFiles?: boolean 40 withFiles?: boolean
39 41
40 accountId?: number 42 accountId?: number
@@ -161,6 +163,10 @@ export class VideosIdListQueryBuilder extends AbstractVideosQueryBuilder {
161 this.whereTagsAllOf(options.tagsAllOf) 163 this.whereTagsAllOf(options.tagsAllOf)
162 } 164 }
163 165
166 if (options.uuids) {
167 this.whereUUIDs(options.uuids)
168 }
169
164 if (options.nsfw === true) { 170 if (options.nsfw === true) {
165 this.whereNSFW() 171 this.whereNSFW()
166 } else if (options.nsfw === false) { 172 } else if (options.nsfw === false) {
@@ -386,6 +392,10 @@ export class VideosIdListQueryBuilder extends AbstractVideosQueryBuilder {
386 ) 392 )
387 } 393 }
388 394
395 private whereUUIDs (uuids: string[]) {
396 this.and.push('"video"."uuid" IN (' + createSafeIn(this.sequelize, uuids) + ')')
397 }
398
389 private whereCategoryOneOf (categoryOneOf: number[]) { 399 private whereCategoryOneOf (categoryOneOf: number[]) {
390 this.and.push('"video"."category" IN (:categoryOneOf)') 400 this.and.push('"video"."category" IN (:categoryOneOf)')
391 this.replacements.categoryOneOf = categoryOneOf 401 this.replacements.categoryOneOf = categoryOneOf
diff --git a/server/models/video/video-channel.ts b/server/models/video/video-channel.ts
index 9aa271711..327f49304 100644
--- a/server/models/video/video-channel.ts
+++ b/server/models/video/video-channel.ts
@@ -59,6 +59,7 @@ type AvailableForListOptions = {
59 actorId: number 59 actorId: number
60 search?: string 60 search?: string
61 host?: string 61 host?: string
62 names?: string[]
62} 63}
63 64
64type AvailableWithStatsOptions = { 65type AvailableWithStatsOptions = {
@@ -84,18 +85,20 @@ export type SummaryOptions = {
84 // Only list local channels OR channels that are on an instance followed by actorId 85 // Only list local channels OR channels that are on an instance followed by actorId
85 const inQueryInstanceFollow = buildServerIdsFollowedBy(options.actorId) 86 const inQueryInstanceFollow = buildServerIdsFollowedBy(options.actorId)
86 87
87 const whereActor = { 88 const whereActorAnd: WhereOptions[] = [
88 [Op.or]: [ 89 {
89 { 90 [Op.or]: [
90 serverId: null 91 {
91 }, 92 serverId: null
92 { 93 },
93 serverId: { 94 {
94 [Op.in]: Sequelize.literal(inQueryInstanceFollow) 95 serverId: {
96 [Op.in]: Sequelize.literal(inQueryInstanceFollow)
97 }
95 } 98 }
96 } 99 ]
97 ] 100 }
98 } 101 ]
99 102
100 let serverRequired = false 103 let serverRequired = false
101 let whereServer: WhereOptions 104 let whereServer: WhereOptions
@@ -106,8 +109,16 @@ export type SummaryOptions = {
106 } 109 }
107 110
108 if (options.host === WEBSERVER.HOST) { 111 if (options.host === WEBSERVER.HOST) {
109 Object.assign(whereActor, { 112 whereActorAnd.push({
110 [Op.and]: [ { serverId: null } ] 113 serverId: null
114 })
115 }
116
117 if (options.names) {
118 whereActorAnd.push({
119 preferredUsername: {
120 [Op.in]: options.names
121 }
111 }) 122 })
112 } 123 }
113 124
@@ -118,7 +129,9 @@ export type SummaryOptions = {
118 exclude: unusedActorAttributesForAPI 129 exclude: unusedActorAttributesForAPI
119 }, 130 },
120 model: ActorModel, 131 model: ActorModel,
121 where: whereActor, 132 where: {
133 [Op.and]: whereActorAnd
134 },
122 include: [ 135 include: [
123 { 136 {
124 model: ServerModel, 137 model: ServerModel,
@@ -454,26 +467,23 @@ ON "Account->Actor"."serverId" = "Account->Actor->Server"."id"`
454 467
455 static searchForApi (options: { 468 static searchForApi (options: {
456 actorId: number 469 actorId: number
457 search: string 470 search?: string
458 start: number 471 start: number
459 count: number 472 count: number
460 sort: string 473 sort: string
461 474
462 host?: string 475 host?: string
476 names?: string[]
463 }) { 477 }) {
464 const attributesInclude = [] 478 let attributesInclude: any[] = [ literal('0 as similarity') ]
465 const escapedSearch = VideoChannelModel.sequelize.escape(options.search) 479 let where: WhereOptions
466 const escapedLikeSearch = VideoChannelModel.sequelize.escape('%' + options.search + '%')
467 attributesInclude.push(createSimilarityAttribute('VideoChannelModel.name', options.search))
468 480
469 const query = { 481 if (options.search) {
470 attributes: { 482 const escapedSearch = VideoChannelModel.sequelize.escape(options.search)
471 include: attributesInclude 483 const escapedLikeSearch = VideoChannelModel.sequelize.escape('%' + options.search + '%')
472 }, 484 attributesInclude = [ createSimilarityAttribute('VideoChannelModel.name', options.search) ]
473 offset: options.start, 485
474 limit: options.count, 486 where = {
475 order: getSort(options.sort),
476 where: {
477 [Op.or]: [ 487 [Op.or]: [
478 Sequelize.literal( 488 Sequelize.literal(
479 'lower(immutable_unaccent("VideoChannelModel"."name")) % lower(immutable_unaccent(' + escapedSearch + '))' 489 'lower(immutable_unaccent("VideoChannelModel"."name")) % lower(immutable_unaccent(' + escapedSearch + '))'
@@ -485,9 +495,19 @@ ON "Account->Actor"."serverId" = "Account->Actor->Server"."id"`
485 } 495 }
486 } 496 }
487 497
498 const query = {
499 attributes: {
500 include: attributesInclude
501 },
502 offset: options.start,
503 limit: options.count,
504 order: getSort(options.sort),
505 where
506 }
507
488 return VideoChannelModel 508 return VideoChannelModel
489 .scope({ 509 .scope({
490 method: [ ScopeNames.FOR_API, { actorId: options.actorId, host: options.host } as AvailableForListOptions ] 510 method: [ ScopeNames.FOR_API, { actorId: options.actorId, host: options.host, names: options.names } as AvailableForListOptions ]
491 }) 511 })
492 .findAndCountAll(query) 512 .findAndCountAll(query)
493 .then(({ rows, count }) => { 513 .then(({ rows, count }) => {
diff --git a/server/models/video/video-playlist.ts b/server/models/video/video-playlist.ts
index a2dc7075d..caa79952d 100644
--- a/server/models/video/video-playlist.ts
+++ b/server/models/video/video-playlist.ts
@@ -83,6 +83,7 @@ type AvailableForListOptions = {
83 listMyPlaylists?: boolean 83 listMyPlaylists?: boolean
84 search?: string 84 search?: string
85 host?: string 85 host?: string
86 uuids?: string[]
86 withVideos?: boolean 87 withVideos?: boolean
87} 88}
88 89
@@ -200,18 +201,26 @@ function getVideoLengthSelect () {
200 }) 201 })
201 } 202 }
202 203
204 if (options.uuids) {
205 whereAnd.push({
206 uuid: {
207 [Op.in]: options.uuids
208 }
209 })
210 }
211
203 if (options.withVideos === true) { 212 if (options.withVideos === true) {
204 whereAnd.push( 213 whereAnd.push(
205 literal(`(${getVideoLengthSelect()}) != 0`) 214 literal(`(${getVideoLengthSelect()}) != 0`)
206 ) 215 )
207 } 216 }
208 217
209 const attributesInclude = [] 218 let attributesInclude: any[] = [ literal('0 as similarity') ]
210 219
211 if (options.search) { 220 if (options.search) {
212 const escapedSearch = VideoPlaylistModel.sequelize.escape(options.search) 221 const escapedSearch = VideoPlaylistModel.sequelize.escape(options.search)
213 const escapedLikeSearch = VideoPlaylistModel.sequelize.escape('%' + options.search + '%') 222 const escapedLikeSearch = VideoPlaylistModel.sequelize.escape('%' + options.search + '%')
214 attributesInclude.push(createSimilarityAttribute('VideoPlaylistModel.name', options.search)) 223 attributesInclude = [ createSimilarityAttribute('VideoPlaylistModel.name', options.search) ]
215 224
216 whereAnd.push({ 225 whereAnd.push({
217 [Op.or]: [ 226 [Op.or]: [
@@ -359,6 +368,7 @@ export class VideoPlaylistModel extends Model<Partial<AttributesOnly<VideoPlayli
359 listMyPlaylists?: boolean 368 listMyPlaylists?: boolean
360 search?: string 369 search?: string
361 host?: string 370 host?: string
371 uuids?: string[]
362 withVideos?: boolean // false by default 372 withVideos?: boolean // false by default
363 }) { 373 }) {
364 const query = { 374 const query = {
@@ -379,6 +389,7 @@ export class VideoPlaylistModel extends Model<Partial<AttributesOnly<VideoPlayli
379 listMyPlaylists: options.listMyPlaylists, 389 listMyPlaylists: options.listMyPlaylists,
380 search: options.search, 390 search: options.search,
381 host: options.host, 391 host: options.host,
392 uuids: options.uuids,
382 withVideos: options.withVideos || false 393 withVideos: options.withVideos || false
383 } as AvailableForListOptions 394 } as AvailableForListOptions
384 ] 395 ]
@@ -402,6 +413,7 @@ export class VideoPlaylistModel extends Model<Partial<AttributesOnly<VideoPlayli
402 sort: string 413 sort: string
403 search?: string 414 search?: string
404 host?: string 415 host?: string
416 uuids?: string[]
405 }) { 417 }) {
406 return VideoPlaylistModel.listForApi({ 418 return VideoPlaylistModel.listForApi({
407 ...options, 419 ...options,
diff --git a/server/models/video/video.ts b/server/models/video/video.ts
index c444f381e..fe92ead04 100644
--- a/server/models/video/video.ts
+++ b/server/models/video/video.ts
@@ -1132,6 +1132,7 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> {
1132 durationMax?: number // seconds 1132 durationMax?: number // seconds
1133 user?: MUserAccountId 1133 user?: MUserAccountId
1134 filter?: VideoFilter 1134 filter?: VideoFilter
1135 uuids?: string[]
1135 }) { 1136 }) {
1136 const serverActor = await getServerActor() 1137 const serverActor = await getServerActor()
1137 1138
@@ -1167,6 +1168,8 @@ export class VideoModel extends Model<Partial<AttributesOnly<VideoModel>>> {
1167 durationMin: options.durationMin, 1168 durationMin: options.durationMin,
1168 durationMax: options.durationMax, 1169 durationMax: options.durationMax,
1169 1170
1171 uuids: options.uuids,
1172
1170 search: options.search 1173 search: options.search
1171 } 1174 }
1172 1175