aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/models/video/video-playlist.ts
diff options
context:
space:
mode:
Diffstat (limited to 'server/models/video/video-playlist.ts')
-rw-r--r--server/models/video/video-playlist.ts64
1 files changed, 35 insertions, 29 deletions
diff --git a/server/models/video/video-playlist.ts b/server/models/video/video-playlist.ts
index af81c9906..630684a88 100644
--- a/server/models/video/video-playlist.ts
+++ b/server/models/video/video-playlist.ts
@@ -17,10 +17,9 @@ import {
17 Table, 17 Table,
18 UpdatedAt 18 UpdatedAt
19} from 'sequelize-typescript' 19} from 'sequelize-typescript'
20import { setAsUpdated } from '@server/helpers/database-utils'
21import { buildUUID, uuidToShort } from '@server/helpers/uuid' 20import { buildUUID, uuidToShort } from '@server/helpers/uuid'
22import { MAccountId, MChannelId } from '@server/types/models' 21import { MAccountId, MChannelId } from '@server/types/models'
23import { AttributesOnly } from '@shared/core-utils' 22import { AttributesOnly, buildPlaylistEmbedPath, buildPlaylistWatchPath, pick } from '@shared/core-utils'
24import { ActivityIconObject } from '../../../shared/models/activitypub/objects' 23import { ActivityIconObject } from '../../../shared/models/activitypub/objects'
25import { PlaylistObject } from '../../../shared/models/activitypub/objects/playlist-object' 24import { PlaylistObject } from '../../../shared/models/activitypub/objects/playlist-object'
26import { VideoPlaylistPrivacy } from '../../../shared/models/videos/playlist/video-playlist-privacy.model' 25import { VideoPlaylistPrivacy } from '../../../shared/models/videos/playlist/video-playlist-privacy.model'
@@ -53,6 +52,7 @@ import {
53} from '../../types/models/video/video-playlist' 52} from '../../types/models/video/video-playlist'
54import { AccountModel, ScopeNames as AccountScopeNames, SummaryOptions } from '../account/account' 53import { AccountModel, ScopeNames as AccountScopeNames, SummaryOptions } from '../account/account'
55import { ActorModel } from '../actor/actor' 54import { ActorModel } from '../actor/actor'
55import { setAsUpdated } from '../shared'
56import { 56import {
57 buildServerIdsFollowedBy, 57 buildServerIdsFollowedBy,
58 buildTrigramSearchIndex, 58 buildTrigramSearchIndex,
@@ -82,6 +82,8 @@ type AvailableForListOptions = {
82 videoChannelId?: number 82 videoChannelId?: number
83 listMyPlaylists?: boolean 83 listMyPlaylists?: boolean
84 search?: string 84 search?: string
85 host?: string
86 uuids?: string[]
85 withVideos?: boolean 87 withVideos?: boolean
86} 88}
87 89
@@ -141,9 +143,19 @@ function getVideoLengthSelect () {
141 ] 143 ]
142 }, 144 },
143 [ScopeNames.AVAILABLE_FOR_LIST]: (options: AvailableForListOptions) => { 145 [ScopeNames.AVAILABLE_FOR_LIST]: (options: AvailableForListOptions) => {
146 const whereAnd: WhereOptions[] = []
147
148 const whereServer = options.host && options.host !== WEBSERVER.HOST
149 ? { host: options.host }
150 : undefined
151
144 let whereActor: WhereOptions = {} 152 let whereActor: WhereOptions = {}
145 153
146 const whereAnd: WhereOptions[] = [] 154 if (options.host === WEBSERVER.HOST) {
155 whereActor = {
156 [Op.and]: [ { serverId: null } ]
157 }
158 }
147 159
148 if (options.listMyPlaylists !== true) { 160 if (options.listMyPlaylists !== true) {
149 whereAnd.push({ 161 whereAnd.push({
@@ -168,9 +180,7 @@ function getVideoLengthSelect () {
168 }) 180 })
169 } 181 }
170 182
171 whereActor = { 183 Object.assign(whereActor, { [Op.or]: whereActorOr })
172 [Op.or]: whereActorOr
173 }
174 } 184 }
175 185
176 if (options.accountId) { 186 if (options.accountId) {
@@ -191,18 +201,26 @@ function getVideoLengthSelect () {
191 }) 201 })
192 } 202 }
193 203
204 if (options.uuids) {
205 whereAnd.push({
206 uuid: {
207 [Op.in]: options.uuids
208 }
209 })
210 }
211
194 if (options.withVideos === true) { 212 if (options.withVideos === true) {
195 whereAnd.push( 213 whereAnd.push(
196 literal(`(${getVideoLengthSelect()}) != 0`) 214 literal(`(${getVideoLengthSelect()}) != 0`)
197 ) 215 )
198 } 216 }
199 217
200 const attributesInclude = [] 218 let attributesInclude: any[] = [ literal('0 as similarity') ]
201 219
202 if (options.search) { 220 if (options.search) {
203 const escapedSearch = VideoPlaylistModel.sequelize.escape(options.search) 221 const escapedSearch = VideoPlaylistModel.sequelize.escape(options.search)
204 const escapedLikeSearch = VideoPlaylistModel.sequelize.escape('%' + options.search + '%') 222 const escapedLikeSearch = VideoPlaylistModel.sequelize.escape('%' + options.search + '%')
205 attributesInclude.push(createSimilarityAttribute('VideoPlaylistModel.name', options.search)) 223 attributesInclude = [ createSimilarityAttribute('VideoPlaylistModel.name', options.search) ]
206 224
207 whereAnd.push({ 225 whereAnd.push({
208 [Op.or]: [ 226 [Op.or]: [
@@ -228,7 +246,7 @@ function getVideoLengthSelect () {
228 include: [ 246 include: [
229 { 247 {
230 model: AccountModel.scope({ 248 model: AccountModel.scope({
231 method: [ AccountScopeNames.SUMMARY, { whereActor } as SummaryOptions ] 249 method: [ AccountScopeNames.SUMMARY, { whereActor, whereServer } as SummaryOptions ]
232 }), 250 }),
233 required: true 251 required: true
234 }, 252 },
@@ -339,17 +357,10 @@ export class VideoPlaylistModel extends Model<Partial<AttributesOnly<VideoPlayli
339 }) 357 })
340 Thumbnail: ThumbnailModel 358 Thumbnail: ThumbnailModel
341 359
342 static listForApi (options: { 360 static listForApi (options: AvailableForListOptions & {
343 followerActorId: number
344 start: number 361 start: number
345 count: number 362 count: number
346 sort: string 363 sort: string
347 type?: VideoPlaylistType
348 accountId?: number
349 videoChannelId?: number
350 listMyPlaylists?: boolean
351 search?: string
352 withVideos?: boolean // false by default
353 }) { 364 }) {
354 const query = { 365 const query = {
355 offset: options.start, 366 offset: options.start,
@@ -362,12 +373,8 @@ export class VideoPlaylistModel extends Model<Partial<AttributesOnly<VideoPlayli
362 method: [ 373 method: [
363 ScopeNames.AVAILABLE_FOR_LIST, 374 ScopeNames.AVAILABLE_FOR_LIST,
364 { 375 {
365 type: options.type, 376 ...pick(options, [ 'type', 'followerActorId', 'accountId', 'videoChannelId', 'listMyPlaylists', 'search', 'host', 'uuids' ]),
366 followerActorId: options.followerActorId, 377
367 accountId: options.accountId,
368 videoChannelId: options.videoChannelId,
369 listMyPlaylists: options.listMyPlaylists,
370 search: options.search,
371 withVideos: options.withVideos || false 378 withVideos: options.withVideos || false
372 } as AvailableForListOptions 379 } as AvailableForListOptions
373 ] 380 ]
@@ -384,15 +391,14 @@ export class VideoPlaylistModel extends Model<Partial<AttributesOnly<VideoPlayli
384 }) 391 })
385 } 392 }
386 393
387 static searchForApi (options: { 394 static searchForApi (options: Pick<AvailableForListOptions, 'followerActorId' | 'search'| 'host'| 'uuids'> & {
388 followerActorId: number
389 start: number 395 start: number
390 count: number 396 count: number
391 sort: string 397 sort: string
392 search?: string
393 }) { 398 }) {
394 return VideoPlaylistModel.listForApi({ 399 return VideoPlaylistModel.listForApi({
395 ...options, 400 ...options,
401
396 type: VideoPlaylistType.REGULAR, 402 type: VideoPlaylistType.REGULAR,
397 listMyPlaylists: false, 403 listMyPlaylists: false,
398 withVideos: true 404 withVideos: true
@@ -560,12 +566,12 @@ export class VideoPlaylistModel extends Model<Partial<AttributesOnly<VideoPlayli
560 return join(STATIC_PATHS.THUMBNAILS, this.Thumbnail.filename) 566 return join(STATIC_PATHS.THUMBNAILS, this.Thumbnail.filename)
561 } 567 }
562 568
563 getWatchUrl () { 569 getWatchStaticPath () {
564 return WEBSERVER.URL + '/w/p/' + this.uuid 570 return buildPlaylistWatchPath({ shortUUID: uuidToShort(this.uuid) })
565 } 571 }
566 572
567 getEmbedStaticPath () { 573 getEmbedStaticPath () {
568 return '/video-playlists/embed/' + this.uuid 574 return buildPlaylistEmbedPath(this)
569 } 575 }
570 576
571 static async getStats () { 577 static async getStats () {