diff options
Diffstat (limited to 'server/models')
-rw-r--r-- | server/models/account/account.ts | 3 | ||||
-rw-r--r-- | server/models/account/user-video-history.ts | 55 | ||||
-rw-r--r-- | server/models/account/user.ts | 23 | ||||
-rw-r--r-- | server/models/activitypub/actor-follow.ts | 90 | ||||
-rw-r--r-- | server/models/video/video-format-utils.ts | 9 | ||||
-rw-r--r-- | server/models/video/video.ts | 111 |
6 files changed, 232 insertions, 59 deletions
diff --git a/server/models/account/account.ts b/server/models/account/account.ts index 27c75d886..5a237d733 100644 --- a/server/models/account/account.ts +++ b/server/models/account/account.ts | |||
@@ -248,7 +248,8 @@ export class AccountModel extends Model<AccountModel> { | |||
248 | displayName: this.getDisplayName(), | 248 | displayName: this.getDisplayName(), |
249 | description: this.description, | 249 | description: this.description, |
250 | createdAt: this.createdAt, | 250 | createdAt: this.createdAt, |
251 | updatedAt: this.updatedAt | 251 | updatedAt: this.updatedAt, |
252 | userId: this.userId ? this.userId : undefined | ||
252 | } | 253 | } |
253 | 254 | ||
254 | return Object.assign(actor, account) | 255 | return Object.assign(actor, account) |
diff --git a/server/models/account/user-video-history.ts b/server/models/account/user-video-history.ts new file mode 100644 index 000000000..0476cad9d --- /dev/null +++ b/server/models/account/user-video-history.ts | |||
@@ -0,0 +1,55 @@ | |||
1 | import { AllowNull, BelongsTo, Column, CreatedAt, ForeignKey, IsInt, Min, Model, Table, UpdatedAt } from 'sequelize-typescript' | ||
2 | import { VideoModel } from '../video/video' | ||
3 | import { UserModel } from './user' | ||
4 | |||
5 | @Table({ | ||
6 | tableName: 'userVideoHistory', | ||
7 | indexes: [ | ||
8 | { | ||
9 | fields: [ 'userId', 'videoId' ], | ||
10 | unique: true | ||
11 | }, | ||
12 | { | ||
13 | fields: [ 'userId' ] | ||
14 | }, | ||
15 | { | ||
16 | fields: [ 'videoId' ] | ||
17 | } | ||
18 | ] | ||
19 | }) | ||
20 | export class UserVideoHistoryModel extends Model<UserVideoHistoryModel> { | ||
21 | @CreatedAt | ||
22 | createdAt: Date | ||
23 | |||
24 | @UpdatedAt | ||
25 | updatedAt: Date | ||
26 | |||
27 | @AllowNull(false) | ||
28 | @IsInt | ||
29 | @Column | ||
30 | currentTime: number | ||
31 | |||
32 | @ForeignKey(() => VideoModel) | ||
33 | @Column | ||
34 | videoId: number | ||
35 | |||
36 | @BelongsTo(() => VideoModel, { | ||
37 | foreignKey: { | ||
38 | allowNull: false | ||
39 | }, | ||
40 | onDelete: 'CASCADE' | ||
41 | }) | ||
42 | Video: VideoModel | ||
43 | |||
44 | @ForeignKey(() => UserModel) | ||
45 | @Column | ||
46 | userId: number | ||
47 | |||
48 | @BelongsTo(() => UserModel, { | ||
49 | foreignKey: { | ||
50 | allowNull: false | ||
51 | }, | ||
52 | onDelete: 'CASCADE' | ||
53 | }) | ||
54 | User: UserModel | ||
55 | } | ||
diff --git a/server/models/account/user.ts b/server/models/account/user.ts index e56b0bf40..39654cfcf 100644 --- a/server/models/account/user.ts +++ b/server/models/account/user.ts | |||
@@ -181,7 +181,25 @@ export class UserModel extends Model<UserModel> { | |||
181 | return this.count() | 181 | return this.count() |
182 | } | 182 | } |
183 | 183 | ||
184 | static listForApi (start: number, count: number, sort: string) { | 184 | static listForApi (start: number, count: number, sort: string, search?: string) { |
185 | let where = undefined | ||
186 | if (search) { | ||
187 | where = { | ||
188 | [Sequelize.Op.or]: [ | ||
189 | { | ||
190 | email: { | ||
191 | [Sequelize.Op.iLike]: '%' + search + '%' | ||
192 | } | ||
193 | }, | ||
194 | { | ||
195 | username: { | ||
196 | [ Sequelize.Op.iLike ]: '%' + search + '%' | ||
197 | } | ||
198 | } | ||
199 | ] | ||
200 | } | ||
201 | } | ||
202 | |||
185 | const query = { | 203 | const query = { |
186 | attributes: { | 204 | attributes: { |
187 | include: [ | 205 | include: [ |
@@ -204,7 +222,8 @@ export class UserModel extends Model<UserModel> { | |||
204 | }, | 222 | }, |
205 | offset: start, | 223 | offset: start, |
206 | limit: count, | 224 | limit: count, |
207 | order: getSort(sort) | 225 | order: getSort(sort), |
226 | where | ||
208 | } | 227 | } |
209 | 228 | ||
210 | return UserModel.findAndCountAll(query) | 229 | return UserModel.findAndCountAll(query) |
diff --git a/server/models/activitypub/actor-follow.ts b/server/models/activitypub/actor-follow.ts index 27bb43dae..3373355ef 100644 --- a/server/models/activitypub/actor-follow.ts +++ b/server/models/activitypub/actor-follow.ts | |||
@@ -280,7 +280,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> { | |||
280 | return ActorFollowModel.findAll(query) | 280 | return ActorFollowModel.findAll(query) |
281 | } | 281 | } |
282 | 282 | ||
283 | static listFollowingForApi (id: number, start: number, count: number, sort: string) { | 283 | static listFollowingForApi (id: number, start: number, count: number, sort: string, search?: string) { |
284 | const query = { | 284 | const query = { |
285 | distinct: true, | 285 | distinct: true, |
286 | offset: start, | 286 | offset: start, |
@@ -299,7 +299,17 @@ export class ActorFollowModel extends Model<ActorFollowModel> { | |||
299 | model: ActorModel, | 299 | model: ActorModel, |
300 | as: 'ActorFollowing', | 300 | as: 'ActorFollowing', |
301 | required: true, | 301 | required: true, |
302 | include: [ ServerModel ] | 302 | include: [ |
303 | { | ||
304 | model: ServerModel, | ||
305 | required: true, | ||
306 | where: search ? { | ||
307 | host: { | ||
308 | [Sequelize.Op.iLike]: '%' + search + '%' | ||
309 | } | ||
310 | } : undefined | ||
311 | } | ||
312 | ] | ||
303 | } | 313 | } |
304 | ] | 314 | ] |
305 | } | 315 | } |
@@ -313,6 +323,49 @@ export class ActorFollowModel extends Model<ActorFollowModel> { | |||
313 | }) | 323 | }) |
314 | } | 324 | } |
315 | 325 | ||
326 | static listFollowersForApi (id: number, start: number, count: number, sort: string, search?: string) { | ||
327 | const query = { | ||
328 | distinct: true, | ||
329 | offset: start, | ||
330 | limit: count, | ||
331 | order: getSort(sort), | ||
332 | include: [ | ||
333 | { | ||
334 | model: ActorModel, | ||
335 | required: true, | ||
336 | as: 'ActorFollower', | ||
337 | include: [ | ||
338 | { | ||
339 | model: ServerModel, | ||
340 | required: true, | ||
341 | where: search ? { | ||
342 | host: { | ||
343 | [ Sequelize.Op.iLike ]: '%' + search + '%' | ||
344 | } | ||
345 | } : undefined | ||
346 | } | ||
347 | ] | ||
348 | }, | ||
349 | { | ||
350 | model: ActorModel, | ||
351 | as: 'ActorFollowing', | ||
352 | required: true, | ||
353 | where: { | ||
354 | id | ||
355 | } | ||
356 | } | ||
357 | ] | ||
358 | } | ||
359 | |||
360 | return ActorFollowModel.findAndCountAll(query) | ||
361 | .then(({ rows, count }) => { | ||
362 | return { | ||
363 | data: rows, | ||
364 | total: count | ||
365 | } | ||
366 | }) | ||
367 | } | ||
368 | |||
316 | static listSubscriptionsForApi (id: number, start: number, count: number, sort: string) { | 369 | static listSubscriptionsForApi (id: number, start: number, count: number, sort: string) { |
317 | const query = { | 370 | const query = { |
318 | attributes: [], | 371 | attributes: [], |
@@ -370,39 +423,6 @@ export class ActorFollowModel extends Model<ActorFollowModel> { | |||
370 | }) | 423 | }) |
371 | } | 424 | } |
372 | 425 | ||
373 | static listFollowersForApi (id: number, start: number, count: number, sort: string) { | ||
374 | const query = { | ||
375 | distinct: true, | ||
376 | offset: start, | ||
377 | limit: count, | ||
378 | order: getSort(sort), | ||
379 | include: [ | ||
380 | { | ||
381 | model: ActorModel, | ||
382 | required: true, | ||
383 | as: 'ActorFollower', | ||
384 | include: [ ServerModel ] | ||
385 | }, | ||
386 | { | ||
387 | model: ActorModel, | ||
388 | as: 'ActorFollowing', | ||
389 | required: true, | ||
390 | where: { | ||
391 | id | ||
392 | } | ||
393 | } | ||
394 | ] | ||
395 | } | ||
396 | |||
397 | return ActorFollowModel.findAndCountAll(query) | ||
398 | .then(({ rows, count }) => { | ||
399 | return { | ||
400 | data: rows, | ||
401 | total: count | ||
402 | } | ||
403 | }) | ||
404 | } | ||
405 | |||
406 | static listAcceptedFollowerUrlsForApi (actorIds: number[], t: Sequelize.Transaction, start?: number, count?: number) { | 426 | static listAcceptedFollowerUrlsForApi (actorIds: number[], t: Sequelize.Transaction, start?: number, count?: number) { |
407 | return ActorFollowModel.createListAcceptedFollowForApiQuery('followers', actorIds, t, start, count) | 427 | return ActorFollowModel.createListAcceptedFollowForApiQuery('followers', actorIds, t, start, count) |
408 | } | 428 | } |
diff --git a/server/models/video/video-format-utils.ts b/server/models/video/video-format-utils.ts index f23dde9b8..905e84449 100644 --- a/server/models/video/video-format-utils.ts +++ b/server/models/video/video-format-utils.ts | |||
@@ -10,6 +10,7 @@ import { | |||
10 | getVideoLikesActivityPubUrl, | 10 | getVideoLikesActivityPubUrl, |
11 | getVideoSharesActivityPubUrl | 11 | getVideoSharesActivityPubUrl |
12 | } from '../../lib/activitypub' | 12 | } from '../../lib/activitypub' |
13 | import { isArray } from '../../helpers/custom-validators/misc' | ||
13 | 14 | ||
14 | export type VideoFormattingJSONOptions = { | 15 | export type VideoFormattingJSONOptions = { |
15 | completeDescription?: boolean | 16 | completeDescription?: boolean |
@@ -24,6 +25,8 @@ function videoModelToFormattedJSON (video: VideoModel, options?: VideoFormatting | |||
24 | const formattedAccount = video.VideoChannel.Account.toFormattedJSON() | 25 | const formattedAccount = video.VideoChannel.Account.toFormattedJSON() |
25 | const formattedVideoChannel = video.VideoChannel.toFormattedJSON() | 26 | const formattedVideoChannel = video.VideoChannel.toFormattedJSON() |
26 | 27 | ||
28 | const userHistory = isArray(video.UserVideoHistories) ? video.UserVideoHistories[0] : undefined | ||
29 | |||
27 | const videoObject: Video = { | 30 | const videoObject: Video = { |
28 | id: video.id, | 31 | id: video.id, |
29 | uuid: video.uuid, | 32 | uuid: video.uuid, |
@@ -74,7 +77,11 @@ function videoModelToFormattedJSON (video: VideoModel, options?: VideoFormatting | |||
74 | url: formattedVideoChannel.url, | 77 | url: formattedVideoChannel.url, |
75 | host: formattedVideoChannel.host, | 78 | host: formattedVideoChannel.host, |
76 | avatar: formattedVideoChannel.avatar | 79 | avatar: formattedVideoChannel.avatar |
77 | } | 80 | }, |
81 | |||
82 | userHistory: userHistory ? { | ||
83 | currentTime: userHistory.currentTime | ||
84 | } : undefined | ||
78 | } | 85 | } |
79 | 86 | ||
80 | if (options) { | 87 | if (options) { |
diff --git a/server/models/video/video.ts b/server/models/video/video.ts index 6c89c16bf..4f3f75613 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts | |||
@@ -92,6 +92,7 @@ import { | |||
92 | videoModelToFormattedJSON | 92 | videoModelToFormattedJSON |
93 | } from './video-format-utils' | 93 | } from './video-format-utils' |
94 | import * as validator from 'validator' | 94 | import * as validator from 'validator' |
95 | import { UserVideoHistoryModel } from '../account/user-video-history' | ||
95 | 96 | ||
96 | // FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation | 97 | // FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation |
97 | const indexes: Sequelize.DefineIndexesOptions[] = [ | 98 | const indexes: Sequelize.DefineIndexesOptions[] = [ |
@@ -127,7 +128,8 @@ export enum ScopeNames { | |||
127 | WITH_TAGS = 'WITH_TAGS', | 128 | WITH_TAGS = 'WITH_TAGS', |
128 | WITH_FILES = 'WITH_FILES', | 129 | WITH_FILES = 'WITH_FILES', |
129 | WITH_SCHEDULED_UPDATE = 'WITH_SCHEDULED_UPDATE', | 130 | WITH_SCHEDULED_UPDATE = 'WITH_SCHEDULED_UPDATE', |
130 | WITH_BLACKLISTED = 'WITH_BLACKLISTED' | 131 | WITH_BLACKLISTED = 'WITH_BLACKLISTED', |
132 | WITH_USER_HISTORY = 'WITH_USER_HISTORY' | ||
131 | } | 133 | } |
132 | 134 | ||
133 | type ForAPIOptions = { | 135 | type ForAPIOptions = { |
@@ -233,7 +235,14 @@ type AvailableForListIDsOptions = { | |||
233 | ) | 235 | ) |
234 | } | 236 | } |
235 | ] | 237 | ] |
236 | }, | 238 | } |
239 | }, | ||
240 | include: [] | ||
241 | } | ||
242 | |||
243 | // Only list public/published videos | ||
244 | if (!options.filter || options.filter !== 'all-local') { | ||
245 | const privacyWhere = { | ||
237 | // Always list public videos | 246 | // Always list public videos |
238 | privacy: VideoPrivacy.PUBLIC, | 247 | privacy: VideoPrivacy.PUBLIC, |
239 | // Always list published videos, or videos that are being transcoded but on which we don't want to wait for transcoding | 248 | // Always list published videos, or videos that are being transcoded but on which we don't want to wait for transcoding |
@@ -248,8 +257,9 @@ type AvailableForListIDsOptions = { | |||
248 | } | 257 | } |
249 | } | 258 | } |
250 | ] | 259 | ] |
251 | }, | 260 | } |
252 | include: [] | 261 | |
262 | Object.assign(query.where, privacyWhere) | ||
253 | } | 263 | } |
254 | 264 | ||
255 | if (options.filter || options.accountId || options.videoChannelId) { | 265 | if (options.filter || options.accountId || options.videoChannelId) { |
@@ -464,6 +474,8 @@ type AvailableForListIDsOptions = { | |||
464 | include: [ | 474 | include: [ |
465 | { | 475 | { |
466 | model: () => VideoFileModel.unscoped(), | 476 | model: () => VideoFileModel.unscoped(), |
477 | // FIXME: typings | ||
478 | [ 'separate' as any ]: true, // We may have multiple files, having multiple redundancies so let's separate this join | ||
467 | required: false, | 479 | required: false, |
468 | include: [ | 480 | include: [ |
469 | { | 481 | { |
@@ -482,6 +494,20 @@ type AvailableForListIDsOptions = { | |||
482 | required: false | 494 | required: false |
483 | } | 495 | } |
484 | ] | 496 | ] |
497 | }, | ||
498 | [ ScopeNames.WITH_USER_HISTORY ]: (userId: number) => { | ||
499 | return { | ||
500 | include: [ | ||
501 | { | ||
502 | attributes: [ 'currentTime' ], | ||
503 | model: UserVideoHistoryModel.unscoped(), | ||
504 | required: false, | ||
505 | where: { | ||
506 | userId | ||
507 | } | ||
508 | } | ||
509 | ] | ||
510 | } | ||
485 | } | 511 | } |
486 | }) | 512 | }) |
487 | @Table({ | 513 | @Table({ |
@@ -672,11 +698,19 @@ export class VideoModel extends Model<VideoModel> { | |||
672 | name: 'videoId', | 698 | name: 'videoId', |
673 | allowNull: false | 699 | allowNull: false |
674 | }, | 700 | }, |
675 | onDelete: 'cascade', | 701 | onDelete: 'cascade' |
676 | hooks: true | ||
677 | }) | 702 | }) |
678 | VideoViews: VideoViewModel[] | 703 | VideoViews: VideoViewModel[] |
679 | 704 | ||
705 | @HasMany(() => UserVideoHistoryModel, { | ||
706 | foreignKey: { | ||
707 | name: 'videoId', | ||
708 | allowNull: false | ||
709 | }, | ||
710 | onDelete: 'cascade' | ||
711 | }) | ||
712 | UserVideoHistories: UserVideoHistoryModel[] | ||
713 | |||
680 | @HasOne(() => ScheduleVideoUpdateModel, { | 714 | @HasOne(() => ScheduleVideoUpdateModel, { |
681 | foreignKey: { | 715 | foreignKey: { |
682 | name: 'videoId', | 716 | name: 'videoId', |
@@ -762,6 +796,16 @@ export class VideoModel extends Model<VideoModel> { | |||
762 | return VideoModel.scope(ScopeNames.WITH_FILES).findAll() | 796 | return VideoModel.scope(ScopeNames.WITH_FILES).findAll() |
763 | } | 797 | } |
764 | 798 | ||
799 | static listLocal () { | ||
800 | const query = { | ||
801 | where: { | ||
802 | remote: false | ||
803 | } | ||
804 | } | ||
805 | |||
806 | return VideoModel.scope(ScopeNames.WITH_FILES).findAll(query) | ||
807 | } | ||
808 | |||
765 | static listAllAndSharedByActorForOutbox (actorId: number, start: number, count: number) { | 809 | static listAllAndSharedByActorForOutbox (actorId: number, start: number, count: number) { |
766 | function getRawQuery (select: string) { | 810 | function getRawQuery (select: string) { |
767 | const queryVideo = 'SELECT ' + select + ' FROM "video" AS "Video" ' + | 811 | const queryVideo = 'SELECT ' + select + ' FROM "video" AS "Video" ' + |
@@ -930,8 +974,13 @@ export class VideoModel extends Model<VideoModel> { | |||
930 | accountId?: number, | 974 | accountId?: number, |
931 | videoChannelId?: number, | 975 | videoChannelId?: number, |
932 | actorId?: number | 976 | actorId?: number |
933 | trendingDays?: number | 977 | trendingDays?: number, |
978 | userId?: number | ||
934 | }, countVideos = true) { | 979 | }, countVideos = true) { |
980 | if (options.filter && options.filter === 'all-local' && !options.userId) { | ||
981 | throw new Error('Try to filter all-local but no userId is provided') | ||
982 | } | ||
983 | |||
935 | const query: IFindOptions<VideoModel> = { | 984 | const query: IFindOptions<VideoModel> = { |
936 | offset: options.start, | 985 | offset: options.start, |
937 | limit: options.count, | 986 | limit: options.count, |
@@ -961,6 +1010,7 @@ export class VideoModel extends Model<VideoModel> { | |||
961 | accountId: options.accountId, | 1010 | accountId: options.accountId, |
962 | videoChannelId: options.videoChannelId, | 1011 | videoChannelId: options.videoChannelId, |
963 | includeLocalVideos: options.includeLocalVideos, | 1012 | includeLocalVideos: options.includeLocalVideos, |
1013 | userId: options.userId, | ||
964 | trendingDays | 1014 | trendingDays |
965 | } | 1015 | } |
966 | 1016 | ||
@@ -983,6 +1033,8 @@ export class VideoModel extends Model<VideoModel> { | |||
983 | tagsAllOf?: string[] | 1033 | tagsAllOf?: string[] |
984 | durationMin?: number // seconds | 1034 | durationMin?: number // seconds |
985 | durationMax?: number // seconds | 1035 | durationMax?: number // seconds |
1036 | userId?: number, | ||
1037 | filter?: VideoFilter | ||
986 | }) { | 1038 | }) { |
987 | const whereAnd = [] | 1039 | const whereAnd = [] |
988 | 1040 | ||
@@ -1058,7 +1110,9 @@ export class VideoModel extends Model<VideoModel> { | |||
1058 | licenceOneOf: options.licenceOneOf, | 1110 | licenceOneOf: options.licenceOneOf, |
1059 | languageOneOf: options.languageOneOf, | 1111 | languageOneOf: options.languageOneOf, |
1060 | tagsOneOf: options.tagsOneOf, | 1112 | tagsOneOf: options.tagsOneOf, |
1061 | tagsAllOf: options.tagsAllOf | 1113 | tagsAllOf: options.tagsAllOf, |
1114 | userId: options.userId, | ||
1115 | filter: options.filter | ||
1062 | } | 1116 | } |
1063 | 1117 | ||
1064 | return VideoModel.getAvailableForApi(query, queryOptions) | 1118 | return VideoModel.getAvailableForApi(query, queryOptions) |
@@ -1125,7 +1179,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1125 | return VideoModel.scope([ ScopeNames.WITH_ACCOUNT_DETAILS, ScopeNames.WITH_FILES ]).findOne(query) | 1179 | return VideoModel.scope([ ScopeNames.WITH_ACCOUNT_DETAILS, ScopeNames.WITH_FILES ]).findOne(query) |
1126 | } | 1180 | } |
1127 | 1181 | ||
1128 | static loadAndPopulateAccountAndServerAndTags (id: number | string, t?: Sequelize.Transaction) { | 1182 | static loadAndPopulateAccountAndServerAndTags (id: number | string, t?: Sequelize.Transaction, userId?: number) { |
1129 | const where = VideoModel.buildWhereIdOrUUID(id) | 1183 | const where = VideoModel.buildWhereIdOrUUID(id) |
1130 | 1184 | ||
1131 | const options = { | 1185 | const options = { |
@@ -1134,14 +1188,20 @@ export class VideoModel extends Model<VideoModel> { | |||
1134 | transaction: t | 1188 | transaction: t |
1135 | } | 1189 | } |
1136 | 1190 | ||
1191 | const scopes = [ | ||
1192 | ScopeNames.WITH_TAGS, | ||
1193 | ScopeNames.WITH_BLACKLISTED, | ||
1194 | ScopeNames.WITH_FILES, | ||
1195 | ScopeNames.WITH_ACCOUNT_DETAILS, | ||
1196 | ScopeNames.WITH_SCHEDULED_UPDATE | ||
1197 | ] | ||
1198 | |||
1199 | if (userId) { | ||
1200 | scopes.push({ method: [ ScopeNames.WITH_USER_HISTORY, userId ] } as any) // FIXME: typings | ||
1201 | } | ||
1202 | |||
1137 | return VideoModel | 1203 | return VideoModel |
1138 | .scope([ | 1204 | .scope(scopes) |
1139 | ScopeNames.WITH_TAGS, | ||
1140 | ScopeNames.WITH_BLACKLISTED, | ||
1141 | ScopeNames.WITH_FILES, | ||
1142 | ScopeNames.WITH_ACCOUNT_DETAILS, | ||
1143 | ScopeNames.WITH_SCHEDULED_UPDATE | ||
1144 | ]) | ||
1145 | .findOne(options) | 1205 | .findOne(options) |
1146 | } | 1206 | } |
1147 | 1207 | ||
@@ -1216,7 +1276,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1216 | } | 1276 | } |
1217 | 1277 | ||
1218 | private static buildActorWhereWithFilter (filter?: VideoFilter) { | 1278 | private static buildActorWhereWithFilter (filter?: VideoFilter) { |
1219 | if (filter && filter === 'local') { | 1279 | if (filter && (filter === 'local' || filter === 'all-local')) { |
1220 | return { | 1280 | return { |
1221 | serverId: null | 1281 | serverId: null |
1222 | } | 1282 | } |
@@ -1225,7 +1285,11 @@ export class VideoModel extends Model<VideoModel> { | |||
1225 | return {} | 1285 | return {} |
1226 | } | 1286 | } |
1227 | 1287 | ||
1228 | private static async getAvailableForApi (query: IFindOptions<VideoModel>, options: AvailableForListIDsOptions, countVideos = true) { | 1288 | private static async getAvailableForApi ( |
1289 | query: IFindOptions<VideoModel>, | ||
1290 | options: AvailableForListIDsOptions & { userId?: number}, | ||
1291 | countVideos = true | ||
1292 | ) { | ||
1229 | const idsScope = { | 1293 | const idsScope = { |
1230 | method: [ | 1294 | method: [ |
1231 | ScopeNames.AVAILABLE_FOR_LIST_IDS, options | 1295 | ScopeNames.AVAILABLE_FOR_LIST_IDS, options |
@@ -1249,8 +1313,15 @@ export class VideoModel extends Model<VideoModel> { | |||
1249 | 1313 | ||
1250 | if (ids.length === 0) return { data: [], total: count } | 1314 | if (ids.length === 0) return { data: [], total: count } |
1251 | 1315 | ||
1252 | const apiScope = { | 1316 | // FIXME: typings |
1253 | method: [ ScopeNames.FOR_API, { ids, withFiles: options.withFiles } as ForAPIOptions ] | 1317 | const apiScope: any[] = [ |
1318 | { | ||
1319 | method: [ ScopeNames.FOR_API, { ids, withFiles: options.withFiles } as ForAPIOptions ] | ||
1320 | } | ||
1321 | ] | ||
1322 | |||
1323 | if (options.userId) { | ||
1324 | apiScope.push({ method: [ ScopeNames.WITH_USER_HISTORY, options.userId ] }) | ||
1254 | } | 1325 | } |
1255 | 1326 | ||
1256 | const secondQuery = { | 1327 | const secondQuery = { |