diff options
Diffstat (limited to 'server/models/video/video-playlist.ts')
-rw-r--r-- | server/models/video/video-playlist.ts | 64 |
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' |
20 | import { setAsUpdated } from '@server/helpers/database-utils' | ||
21 | import { buildUUID, uuidToShort } from '@server/helpers/uuid' | 20 | import { buildUUID, uuidToShort } from '@server/helpers/uuid' |
22 | import { MAccountId, MChannelId } from '@server/types/models' | 21 | import { MAccountId, MChannelId } from '@server/types/models' |
23 | import { AttributesOnly } from '@shared/core-utils' | 22 | import { AttributesOnly, buildPlaylistEmbedPath, buildPlaylistWatchPath, pick } from '@shared/core-utils' |
24 | import { ActivityIconObject } from '../../../shared/models/activitypub/objects' | 23 | import { ActivityIconObject } from '../../../shared/models/activitypub/objects' |
25 | import { PlaylistObject } from '../../../shared/models/activitypub/objects/playlist-object' | 24 | import { PlaylistObject } from '../../../shared/models/activitypub/objects/playlist-object' |
26 | import { VideoPlaylistPrivacy } from '../../../shared/models/videos/playlist/video-playlist-privacy.model' | 25 | import { 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' |
54 | import { AccountModel, ScopeNames as AccountScopeNames, SummaryOptions } from '../account/account' | 53 | import { AccountModel, ScopeNames as AccountScopeNames, SummaryOptions } from '../account/account' |
55 | import { ActorModel } from '../actor/actor' | 54 | import { ActorModel } from '../actor/actor' |
55 | import { setAsUpdated } from '../shared' | ||
56 | import { | 56 | import { |
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 () { |