aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/models
diff options
context:
space:
mode:
Diffstat (limited to 'server/models')
-rw-r--r--server/models/account/account-blocklist.ts6
-rw-r--r--server/models/account/account-video-rate.ts21
-rw-r--r--server/models/account/account.ts17
-rw-r--r--server/models/account/user-notification.ts10
-rw-r--r--server/models/account/user-video-history.ts7
-rw-r--r--server/models/account/user.ts30
-rw-r--r--server/models/activitypub/actor-follow.ts25
-rw-r--r--server/models/activitypub/actor.ts20
-rw-r--r--server/models/oauth/oauth-token.ts19
-rw-r--r--server/models/redundancy/video-redundancy.ts9
-rw-r--r--server/models/server/plugin.ts10
-rw-r--r--server/models/server/server-blocklist.ts6
-rw-r--r--server/models/server/server.ts5
-rw-r--r--server/models/video/video-abuse.ts8
-rw-r--r--server/models/video/video-blacklist.ts6
-rw-r--r--server/models/video/video-caption.ts8
-rw-r--r--server/models/video/video-change-ownership.ts6
-rw-r--r--server/models/video/video-channel.ts35
-rw-r--r--server/models/video/video-comment.ts83
-rw-r--r--server/models/video/video-file.ts3
-rw-r--r--server/models/video/video-format-utils.ts15
-rw-r--r--server/models/video/video-import.ts12
-rw-r--r--server/models/video/video-playlist-element.ts13
-rw-r--r--server/models/video/video-playlist.ts18
-rw-r--r--server/models/video/video-share.ts14
-rw-r--r--server/models/video/video-streaming-playlist.ts12
-rw-r--r--server/models/video/video.ts111
27 files changed, 292 insertions, 237 deletions
diff --git a/server/models/account/account-blocklist.ts b/server/models/account/account-blocklist.ts
index d5746ad76..bb5371395 100644
--- a/server/models/account/account-blocklist.ts
+++ b/server/models/account/account-blocklist.ts
@@ -3,6 +3,8 @@ import { AccountModel } from './account'
3import { getSort } from '../utils' 3import { getSort } from '../utils'
4import { AccountBlock } from '../../../shared/models/blocklist' 4import { AccountBlock } from '../../../shared/models/blocklist'
5import { Op } from 'sequelize' 5import { Op } from 'sequelize'
6import * as Bluebird from 'bluebird'
7import { MAccountBlocklist, MAccountBlocklistAccounts } from '@server/typings/models'
6 8
7enum ScopeNames { 9enum ScopeNames {
8 WITH_ACCOUNTS = 'WITH_ACCOUNTS' 10 WITH_ACCOUNTS = 'WITH_ACCOUNTS'
@@ -103,7 +105,7 @@ export class AccountBlocklistModel extends Model<AccountBlocklistModel> {
103 }) 105 })
104 } 106 }
105 107
106 static loadByAccountAndTarget (accountId: number, targetAccountId: number) { 108 static loadByAccountAndTarget (accountId: number, targetAccountId: number): Bluebird<MAccountBlocklist> {
107 const query = { 109 const query = {
108 where: { 110 where: {
109 accountId, 111 accountId,
@@ -126,7 +128,7 @@ export class AccountBlocklistModel extends Model<AccountBlocklistModel> {
126 128
127 return AccountBlocklistModel 129 return AccountBlocklistModel
128 .scope([ ScopeNames.WITH_ACCOUNTS ]) 130 .scope([ ScopeNames.WITH_ACCOUNTS ])
129 .findAndCountAll(query) 131 .findAndCountAll<MAccountBlocklistAccounts>(query)
130 .then(({ rows, count }) => { 132 .then(({ rows, count }) => {
131 return { total: count, data: rows } 133 return { total: count, data: rows }
132 }) 134 })
diff --git a/server/models/account/account-video-rate.ts b/server/models/account/account-video-rate.ts
index 4bd8114cf..8b62dd05f 100644
--- a/server/models/account/account-video-rate.ts
+++ b/server/models/account/account-video-rate.ts
@@ -10,6 +10,8 @@ import { buildLocalAccountIdsIn, getSort, throwIfNotValid } from '../utils'
10import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' 10import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
11import { AccountVideoRate } from '../../../shared' 11import { AccountVideoRate } from '../../../shared'
12import { ScopeNames as VideoChannelScopeNames, SummaryOptions, VideoChannelModel } from '../video/video-channel' 12import { ScopeNames as VideoChannelScopeNames, SummaryOptions, VideoChannelModel } from '../video/video-channel'
13import * as Bluebird from 'bluebird'
14import { MAccountVideoRate, MAccountVideoRateAccountUrl, MAccountVideoRateAccountVideo } from '@server/typings/models/video/video-rate'
13 15
14/* 16/*
15 Account rates per video. 17 Account rates per video.
@@ -77,7 +79,7 @@ export class AccountVideoRateModel extends Model<AccountVideoRateModel> {
77 }) 79 })
78 Account: AccountModel 80 Account: AccountModel
79 81
80 static load (accountId: number, videoId: number, transaction?: Transaction) { 82 static load (accountId: number, videoId: number, transaction?: Transaction): Bluebird<MAccountVideoRate> {
81 const options: FindOptions = { 83 const options: FindOptions = {
82 where: { 84 where: {
83 accountId, 85 accountId,
@@ -89,7 +91,7 @@ export class AccountVideoRateModel extends Model<AccountVideoRateModel> {
89 return AccountVideoRateModel.findOne(options) 91 return AccountVideoRateModel.findOne(options)
90 } 92 }
91 93
92 static loadByAccountAndVideoOrUrl (accountId: number, videoId: number, url: string, transaction?: Transaction) { 94 static loadByAccountAndVideoOrUrl (accountId: number, videoId: number, url: string, t?: Transaction): Bluebird<MAccountVideoRate> {
93 const options: FindOptions = { 95 const options: FindOptions = {
94 where: { 96 where: {
95 [ Op.or]: [ 97 [ Op.or]: [
@@ -103,7 +105,7 @@ export class AccountVideoRateModel extends Model<AccountVideoRateModel> {
103 ] 105 ]
104 } 106 }
105 } 107 }
106 if (transaction) options.transaction = transaction 108 if (t) options.transaction = t
107 109
108 return AccountVideoRateModel.findOne(options) 110 return AccountVideoRateModel.findOne(options)
109 } 111 }
@@ -140,7 +142,12 @@ export class AccountVideoRateModel extends Model<AccountVideoRateModel> {
140 return AccountVideoRateModel.findAndCountAll(query) 142 return AccountVideoRateModel.findAndCountAll(query)
141 } 143 }
142 144
143 static loadLocalAndPopulateVideo (rateType: VideoRateType, accountName: string, videoId: number, transaction?: Transaction) { 145 static loadLocalAndPopulateVideo (
146 rateType: VideoRateType,
147 accountName: string,
148 videoId: number,
149 t?: Transaction
150 ): Bluebird<MAccountVideoRateAccountVideo> {
144 const options: FindOptions = { 151 const options: FindOptions = {
145 where: { 152 where: {
146 videoId, 153 videoId,
@@ -152,7 +159,7 @@ export class AccountVideoRateModel extends Model<AccountVideoRateModel> {
152 required: true, 159 required: true,
153 include: [ 160 include: [
154 { 161 {
155 attributes: [ 'id', 'url', 'preferredUsername' ], 162 attributes: [ 'id', 'url', 'followersUrl', 'preferredUsername' ],
156 model: ActorModel.unscoped(), 163 model: ActorModel.unscoped(),
157 required: true, 164 required: true,
158 where: { 165 where: {
@@ -167,7 +174,7 @@ export class AccountVideoRateModel extends Model<AccountVideoRateModel> {
167 } 174 }
168 ] 175 ]
169 } 176 }
170 if (transaction) options.transaction = transaction 177 if (t) options.transaction = t
171 178
172 return AccountVideoRateModel.findOne(options) 179 return AccountVideoRateModel.findOne(options)
173 } 180 }
@@ -208,7 +215,7 @@ export class AccountVideoRateModel extends Model<AccountVideoRateModel> {
208 ] 215 ]
209 } 216 }
210 217
211 return AccountVideoRateModel.findAndCountAll(query) 218 return AccountVideoRateModel.findAndCountAll<MAccountVideoRateAccountUrl>(query)
212 } 219 }
213 220
214 static cleanOldRatesOf (videoId: number, type: VideoRateType, beforeUpdatedAt: Date) { 221 static cleanOldRatesOf (videoId: number, type: VideoRateType, beforeUpdatedAt: Date) {
diff --git a/server/models/account/account.ts b/server/models/account/account.ts
index 4dc412301..4cc731075 100644
--- a/server/models/account/account.ts
+++ b/server/models/account/account.ts
@@ -3,7 +3,8 @@ import {
3 BeforeDestroy, 3 BeforeDestroy,
4 BelongsTo, 4 BelongsTo,
5 Column, 5 Column,
6 CreatedAt, DataType, 6 CreatedAt,
7 DataType,
7 Default, 8 Default,
8 DefaultScope, 9 DefaultScope,
9 ForeignKey, 10 ForeignKey,
@@ -31,6 +32,8 @@ import { FindOptions, IncludeOptions, Op, Transaction, WhereOptions } from 'sequ
31import { AccountBlocklistModel } from './account-blocklist' 32import { AccountBlocklistModel } from './account-blocklist'
32import { ServerBlocklistModel } from '../server/server-blocklist' 33import { ServerBlocklistModel } from '../server/server-blocklist'
33import { ActorFollowModel } from '../activitypub/actor-follow' 34import { ActorFollowModel } from '../activitypub/actor-follow'
35import { MAccountActor, MAccountDefault } from '../../typings/models'
36import * as Bluebird from 'bluebird'
34 37
35export enum ScopeNames { 38export enum ScopeNames {
36 SUMMARY = 'SUMMARY' 39 SUMMARY = 'SUMMARY'
@@ -229,11 +232,11 @@ export class AccountModel extends Model<AccountModel> {
229 return undefined 232 return undefined
230 } 233 }
231 234
232 static load (id: number, transaction?: Transaction) { 235 static load (id: number, transaction?: Transaction): Bluebird<MAccountDefault> {
233 return AccountModel.findByPk(id, { transaction }) 236 return AccountModel.findByPk(id, { transaction })
234 } 237 }
235 238
236 static loadByNameWithHost (nameWithHost: string) { 239 static loadByNameWithHost (nameWithHost: string): Bluebird<MAccountDefault> {
237 const [ accountName, host ] = nameWithHost.split('@') 240 const [ accountName, host ] = nameWithHost.split('@')
238 241
239 if (!host || host === WEBSERVER.HOST) return AccountModel.loadLocalByName(accountName) 242 if (!host || host === WEBSERVER.HOST) return AccountModel.loadLocalByName(accountName)
@@ -241,7 +244,7 @@ export class AccountModel extends Model<AccountModel> {
241 return AccountModel.loadByNameAndHost(accountName, host) 244 return AccountModel.loadByNameAndHost(accountName, host)
242 } 245 }
243 246
244 static loadLocalByName (name: string) { 247 static loadLocalByName (name: string): Bluebird<MAccountDefault> {
245 const query = { 248 const query = {
246 where: { 249 where: {
247 [ Op.or ]: [ 250 [ Op.or ]: [
@@ -271,7 +274,7 @@ export class AccountModel extends Model<AccountModel> {
271 return AccountModel.findOne(query) 274 return AccountModel.findOne(query)
272 } 275 }
273 276
274 static loadByNameAndHost (name: string, host: string) { 277 static loadByNameAndHost (name: string, host: string): Bluebird<MAccountDefault> {
275 const query = { 278 const query = {
276 include: [ 279 include: [
277 { 280 {
@@ -296,7 +299,7 @@ export class AccountModel extends Model<AccountModel> {
296 return AccountModel.findOne(query) 299 return AccountModel.findOne(query)
297 } 300 }
298 301
299 static loadByUrl (url: string, transaction?: Transaction) { 302 static loadByUrl (url: string, transaction?: Transaction): Bluebird<MAccountDefault> {
300 const query = { 303 const query = {
301 include: [ 304 include: [
302 { 305 {
@@ -329,7 +332,7 @@ export class AccountModel extends Model<AccountModel> {
329 }) 332 })
330 } 333 }
331 334
332 static listLocalsForSitemap (sort: string) { 335 static listLocalsForSitemap (sort: string): Bluebird<MAccountActor[]> {
333 const query = { 336 const query = {
334 attributes: [ ], 337 attributes: [ ],
335 offset: 0, 338 offset: 0,
diff --git a/server/models/account/user-notification.ts b/server/models/account/user-notification.ts
index f38cd7e78..9b13a8376 100644
--- a/server/models/account/user-notification.ts
+++ b/server/models/account/user-notification.ts
@@ -16,6 +16,7 @@ import { ActorModel } from '../activitypub/actor'
16import { ActorFollowModel } from '../activitypub/actor-follow' 16import { ActorFollowModel } from '../activitypub/actor-follow'
17import { AvatarModel } from '../avatar/avatar' 17import { AvatarModel } from '../avatar/avatar'
18import { ServerModel } from '../server/server' 18import { ServerModel } from '../server/server'
19import { UserNotificationIncludes, UserNotificationModelForApi } from '@server/typings/models/user'
19 20
20enum ScopeNames { 21enum ScopeNames {
21 WITH_ALL = 'WITH_ALL' 22 WITH_ALL = 'WITH_ALL'
@@ -371,7 +372,7 @@ export class UserNotificationModel extends Model<UserNotificationModel> {
371 return UserNotificationModel.update({ read: true }, query) 372 return UserNotificationModel.update({ read: true }, query)
372 } 373 }
373 374
374 toFormattedJSON (): UserNotification { 375 toFormattedJSON (this: UserNotificationModelForApi): UserNotification {
375 const video = this.Video 376 const video = this.Video
376 ? Object.assign(this.formatVideo(this.Video),{ channel: this.formatActor(this.Video.VideoChannel) }) 377 ? Object.assign(this.formatVideo(this.Video),{ channel: this.formatActor(this.Video.VideoChannel) })
377 : undefined 378 : undefined
@@ -436,7 +437,7 @@ export class UserNotificationModel extends Model<UserNotificationModel> {
436 } 437 }
437 } 438 }
438 439
439 private formatVideo (video: VideoModel) { 440 formatVideo (this: UserNotificationModelForApi, video: UserNotificationIncludes.VideoInclude) {
440 return { 441 return {
441 id: video.id, 442 id: video.id,
442 uuid: video.uuid, 443 uuid: video.uuid,
@@ -444,7 +445,10 @@ export class UserNotificationModel extends Model<UserNotificationModel> {
444 } 445 }
445 } 446 }
446 447
447 private formatActor (accountOrChannel: AccountModel | VideoChannelModel) { 448 formatActor (
449 this: UserNotificationModelForApi,
450 accountOrChannel: UserNotificationIncludes.AccountIncludeActor | UserNotificationIncludes.VideoChannelIncludeActor
451 ) {
448 const avatar = accountOrChannel.Actor.Avatar 452 const avatar = accountOrChannel.Actor.Avatar
449 ? { path: accountOrChannel.Actor.Avatar.getStaticPath() } 453 ? { path: accountOrChannel.Actor.Avatar.getStaticPath() }
450 : undefined 454 : undefined
diff --git a/server/models/account/user-video-history.ts b/server/models/account/user-video-history.ts
index a862fc45f..3fe4c8db1 100644
--- a/server/models/account/user-video-history.ts
+++ b/server/models/account/user-video-history.ts
@@ -1,7 +1,8 @@
1import { AllowNull, BelongsTo, Column, CreatedAt, ForeignKey, IsInt, Model, Table, UpdatedAt } from 'sequelize-typescript' 1import { AllowNull, BelongsTo, Column, CreatedAt, ForeignKey, IsInt, Model, Table, UpdatedAt } from 'sequelize-typescript'
2import { VideoModel } from '../video/video' 2import { VideoModel } from '../video/video'
3import { UserModel } from './user' 3import { UserModel } from './user'
4import { Transaction, Op, DestroyOptions } from 'sequelize' 4import { DestroyOptions, Op, Transaction } from 'sequelize'
5import { MUserAccountId, MUserId } from '@server/typings/models'
5 6
6@Table({ 7@Table({
7 tableName: 'userVideoHistory', 8 tableName: 'userVideoHistory',
@@ -54,7 +55,7 @@ export class UserVideoHistoryModel extends Model<UserVideoHistoryModel> {
54 }) 55 })
55 User: UserModel 56 User: UserModel
56 57
57 static listForApi (user: UserModel, start: number, count: number) { 58 static listForApi (user: MUserAccountId, start: number, count: number) {
58 return VideoModel.listForApi({ 59 return VideoModel.listForApi({
59 start, 60 start,
60 count, 61 count,
@@ -67,7 +68,7 @@ export class UserVideoHistoryModel extends Model<UserVideoHistoryModel> {
67 }) 68 })
68 } 69 }
69 70
70 static removeUserHistoryBefore (user: UserModel, beforeDate: string, t: Transaction) { 71 static removeUserHistoryBefore (user: MUserId, beforeDate: string, t: Transaction) {
71 const query: DestroyOptions = { 72 const query: DestroyOptions = {
72 where: { 73 where: {
73 userId: user.id 74 userId: user.id
diff --git a/server/models/account/user.ts b/server/models/account/user.ts
index 0041bf577..24b1626e7 100644
--- a/server/models/account/user.ts
+++ b/server/models/account/user.ts
@@ -54,6 +54,8 @@ import { VideoImportModel } from '../video/video-import'
54import { UserAdminFlag } from '../../../shared/models/users/user-flag.model' 54import { UserAdminFlag } from '../../../shared/models/users/user-flag.model'
55import { isThemeNameValid } from '../../helpers/custom-validators/plugins' 55import { isThemeNameValid } from '../../helpers/custom-validators/plugins'
56import { getThemeOrDefault } from '../../lib/plugins/theme-utils' 56import { getThemeOrDefault } from '../../lib/plugins/theme-utils'
57import * as Bluebird from 'bluebird'
58import { MUserChannel, MUserDefault, MUserId, MUserWithNotificationSetting } from '@server/typings/models'
57 59
58enum ScopeNames { 60enum ScopeNames {
59 WITH_VIDEO_CHANNEL = 'WITH_VIDEO_CHANNEL' 61 WITH_VIDEO_CHANNEL = 'WITH_VIDEO_CHANNEL'
@@ -303,7 +305,7 @@ export class UserModel extends Model<UserModel> {
303 }) 305 })
304 } 306 }
305 307
306 static listWithRight (right: UserRight) { 308 static listWithRight (right: UserRight): Bluebird<MUserDefault[]> {
307 const roles = Object.keys(USER_ROLE_LABELS) 309 const roles = Object.keys(USER_ROLE_LABELS)
308 .map(k => parseInt(k, 10) as UserRole) 310 .map(k => parseInt(k, 10) as UserRole)
309 .filter(role => hasUserRight(role, right)) 311 .filter(role => hasUserRight(role, right))
@@ -319,7 +321,7 @@ export class UserModel extends Model<UserModel> {
319 return UserModel.findAll(query) 321 return UserModel.findAll(query)
320 } 322 }
321 323
322 static listUserSubscribersOf (actorId: number) { 324 static listUserSubscribersOf (actorId: number): Bluebird<MUserWithNotificationSetting[]> {
323 const query = { 325 const query = {
324 include: [ 326 include: [
325 { 327 {
@@ -358,7 +360,7 @@ export class UserModel extends Model<UserModel> {
358 return UserModel.unscoped().findAll(query) 360 return UserModel.unscoped().findAll(query)
359 } 361 }
360 362
361 static listByUsernames (usernames: string[]) { 363 static listByUsernames (usernames: string[]): Bluebird<MUserDefault[]> {
362 const query = { 364 const query = {
363 where: { 365 where: {
364 username: usernames 366 username: usernames
@@ -368,11 +370,11 @@ export class UserModel extends Model<UserModel> {
368 return UserModel.findAll(query) 370 return UserModel.findAll(query)
369 } 371 }
370 372
371 static loadById (id: number) { 373 static loadById (id: number): Bluebird<MUserDefault> {
372 return UserModel.findByPk(id) 374 return UserModel.findByPk(id)
373 } 375 }
374 376
375 static loadByUsername (username: string) { 377 static loadByUsername (username: string): Bluebird<MUserDefault> {
376 const query = { 378 const query = {
377 where: { 379 where: {
378 username: { [ Op.iLike ]: username } 380 username: { [ Op.iLike ]: username }
@@ -382,7 +384,7 @@ export class UserModel extends Model<UserModel> {
382 return UserModel.findOne(query) 384 return UserModel.findOne(query)
383 } 385 }
384 386
385 static loadByUsernameAndPopulateChannels (username: string) { 387 static loadByUsernameAndPopulateChannels (username: string): Bluebird<MUserChannel> {
386 const query = { 388 const query = {
387 where: { 389 where: {
388 username: { [ Op.iLike ]: username } 390 username: { [ Op.iLike ]: username }
@@ -392,7 +394,7 @@ export class UserModel extends Model<UserModel> {
392 return UserModel.scope(ScopeNames.WITH_VIDEO_CHANNEL).findOne(query) 394 return UserModel.scope(ScopeNames.WITH_VIDEO_CHANNEL).findOne(query)
393 } 395 }
394 396
395 static loadByEmail (email: string) { 397 static loadByEmail (email: string): Bluebird<MUserDefault> {
396 const query = { 398 const query = {
397 where: { 399 where: {
398 email 400 email
@@ -402,7 +404,7 @@ export class UserModel extends Model<UserModel> {
402 return UserModel.findOne(query) 404 return UserModel.findOne(query)
403 } 405 }
404 406
405 static loadByUsernameOrEmail (username: string, email?: string) { 407 static loadByUsernameOrEmail (username: string, email?: string): Bluebird<MUserDefault> {
406 if (!email) email = username 408 if (!email) email = username
407 409
408 const query = { 410 const query = {
@@ -414,7 +416,7 @@ export class UserModel extends Model<UserModel> {
414 return UserModel.findOne(query) 416 return UserModel.findOne(query)
415 } 417 }
416 418
417 static loadByVideoId (videoId: number) { 419 static loadByVideoId (videoId: number): Bluebird<MUserDefault> {
418 const query = { 420 const query = {
419 include: [ 421 include: [
420 { 422 {
@@ -445,7 +447,7 @@ export class UserModel extends Model<UserModel> {
445 return UserModel.findOne(query) 447 return UserModel.findOne(query)
446 } 448 }
447 449
448 static loadByVideoImportId (videoImportId: number) { 450 static loadByVideoImportId (videoImportId: number): Bluebird<MUserDefault> {
449 const query = { 451 const query = {
450 include: [ 452 include: [
451 { 453 {
@@ -462,7 +464,7 @@ export class UserModel extends Model<UserModel> {
462 return UserModel.findOne(query) 464 return UserModel.findOne(query)
463 } 465 }
464 466
465 static loadByChannelActorId (videoChannelActorId: number) { 467 static loadByChannelActorId (videoChannelActorId: number): Bluebird<MUserDefault> {
466 const query = { 468 const query = {
467 include: [ 469 include: [
468 { 470 {
@@ -486,7 +488,7 @@ export class UserModel extends Model<UserModel> {
486 return UserModel.findOne(query) 488 return UserModel.findOne(query)
487 } 489 }
488 490
489 static loadByAccountActorId (accountActorId: number) { 491 static loadByAccountActorId (accountActorId: number): Bluebird<MUserDefault> {
490 const query = { 492 const query = {
491 include: [ 493 include: [
492 { 494 {
@@ -503,7 +505,7 @@ export class UserModel extends Model<UserModel> {
503 return UserModel.findOne(query) 505 return UserModel.findOne(query)
504 } 506 }
505 507
506 static getOriginalVideoFileTotalFromUser (user: UserModel) { 508 static getOriginalVideoFileTotalFromUser (user: MUserId) {
507 // Don't use sequelize because we need to use a sub query 509 // Don't use sequelize because we need to use a sub query
508 const query = UserModel.generateUserQuotaBaseSQL() 510 const query = UserModel.generateUserQuotaBaseSQL()
509 511
@@ -511,7 +513,7 @@ export class UserModel extends Model<UserModel> {
511 } 513 }
512 514
513 // Returns cumulative size of all video files uploaded in the last 24 hours. 515 // Returns cumulative size of all video files uploaded in the last 24 hours.
514 static getOriginalVideoFileTotalDailyFromUser (user: UserModel) { 516 static getOriginalVideoFileTotalDailyFromUser (user: MUserId) {
515 // Don't use sequelize because we need to use a sub query 517 // Don't use sequelize because we need to use a sub query
516 const query = UserModel.generateUserQuotaBaseSQL('"video"."createdAt" > now() - interval \'24 hours\'') 518 const query = UserModel.generateUserQuotaBaseSQL('"video"."createdAt" > now() - interval \'24 hours\'')
517 519
diff --git a/server/models/activitypub/actor-follow.ts b/server/models/activitypub/actor-follow.ts
index 51b09e09b..8ef770cd4 100644
--- a/server/models/activitypub/actor-follow.ts
+++ b/server/models/activitypub/actor-follow.ts
@@ -27,7 +27,13 @@ import { createSafeIn, getSort } from '../utils'
27import { ActorModel, unusedActorAttributesForAPI } from './actor' 27import { ActorModel, unusedActorAttributesForAPI } from './actor'
28import { VideoChannelModel } from '../video/video-channel' 28import { VideoChannelModel } from '../video/video-channel'
29import { AccountModel } from '../account/account' 29import { AccountModel } from '../account/account'
30import { IncludeOptions, Op, Transaction, QueryTypes } from 'sequelize' 30import { IncludeOptions, Op, QueryTypes, Transaction } from 'sequelize'
31import {
32 MActorFollowActorsDefault,
33 MActorFollowActorsDefaultSubscription,
34 MActorFollowFollowingHost,
35 MActorFollowSubscriptions
36} from '@server/typings/models'
31 37
32@Table({ 38@Table({
33 tableName: 'actorFollow', 39 tableName: 'actorFollow',
@@ -143,7 +149,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
143 if (numberOfActorFollowsRemoved) logger.info('Removed bad %d actor follows.', numberOfActorFollowsRemoved) 149 if (numberOfActorFollowsRemoved) logger.info('Removed bad %d actor follows.', numberOfActorFollowsRemoved)
144 } 150 }
145 151
146 static loadByActorAndTarget (actorId: number, targetActorId: number, t?: Transaction) { 152 static loadByActorAndTarget (actorId: number, targetActorId: number, t?: Transaction): Bluebird<MActorFollowActorsDefault> {
147 const query = { 153 const query = {
148 where: { 154 where: {
149 actorId, 155 actorId,
@@ -167,7 +173,12 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
167 return ActorFollowModel.findOne(query) 173 return ActorFollowModel.findOne(query)
168 } 174 }
169 175
170 static loadByActorAndTargetNameAndHostForAPI (actorId: number, targetName: string, targetHost: string, t?: Transaction) { 176 static loadByActorAndTargetNameAndHostForAPI (
177 actorId: number,
178 targetName: string,
179 targetHost: string,
180 t?: Transaction
181 ): Bluebird<MActorFollowActorsDefaultSubscription> {
171 const actorFollowingPartInclude: IncludeOptions = { 182 const actorFollowingPartInclude: IncludeOptions = {
172 model: ActorModel, 183 model: ActorModel,
173 required: true, 184 required: true,
@@ -220,7 +231,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
220 }) 231 })
221 } 232 }
222 233
223 static listSubscribedIn (actorId: number, targets: { name: string, host?: string }[]) { 234 static listSubscribedIn (actorId: number, targets: { name: string, host?: string }[]): Bluebird<MActorFollowFollowingHost[]> {
224 const whereTab = targets 235 const whereTab = targets
225 .map(t => { 236 .map(t => {
226 if (t.host) { 237 if (t.host) {
@@ -314,7 +325,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
314 ] 325 ]
315 } 326 }
316 327
317 return ActorFollowModel.findAndCountAll(query) 328 return ActorFollowModel.findAndCountAll<MActorFollowActorsDefault>(query)
318 .then(({ rows, count }) => { 329 .then(({ rows, count }) => {
319 return { 330 return {
320 data: rows, 331 data: rows,
@@ -357,7 +368,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
357 ] 368 ]
358 } 369 }
359 370
360 return ActorFollowModel.findAndCountAll(query) 371 return ActorFollowModel.findAndCountAll<MActorFollowActorsDefault>(query)
361 .then(({ rows, count }) => { 372 .then(({ rows, count }) => {
362 return { 373 return {
363 data: rows, 374 data: rows,
@@ -414,7 +425,7 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
414 ] 425 ]
415 } 426 }
416 427
417 return ActorFollowModel.findAndCountAll(query) 428 return ActorFollowModel.findAndCountAll<MActorFollowSubscriptions>(query)
418 .then(({ rows, count }) => { 429 .then(({ rows, count }) => {
419 return { 430 return {
420 data: rows.map(r => r.ActorFollowing.VideoChannel), 431 data: rows.map(r => r.ActorFollowing.VideoChannel),
diff --git a/server/models/activitypub/actor.ts b/server/models/activitypub/actor.ts
index 9cc53f78a..2312127b4 100644
--- a/server/models/activitypub/actor.ts
+++ b/server/models/activitypub/actor.ts
@@ -36,6 +36,8 @@ import { isOutdated, throwIfNotValid } from '../utils'
36import { VideoChannelModel } from '../video/video-channel' 36import { VideoChannelModel } from '../video/video-channel'
37import { ActorFollowModel } from './actor-follow' 37import { ActorFollowModel } from './actor-follow'
38import { VideoModel } from '../video/video' 38import { VideoModel } from '../video/video'
39import { MActor, MActorAccountChannelId, MActorFull } from '../../typings/models'
40import * as Bluebird from 'bluebird'
39 41
40enum ScopeNames { 42enum ScopeNames {
41 FULL = 'FULL' 43 FULL = 'FULL'
@@ -252,11 +254,15 @@ export class ActorModel extends Model<ActorModel> {
252 }) 254 })
253 VideoChannel: VideoChannelModel 255 VideoChannel: VideoChannelModel
254 256
255 static load (id: number) { 257 static load (id: number): Bluebird<MActor> {
256 return ActorModel.unscoped().findByPk(id) 258 return ActorModel.unscoped().findByPk(id)
257 } 259 }
258 260
259 static loadAccountActorByVideoId (videoId: number, transaction: Sequelize.Transaction) { 261 static loadFull (id: number): Bluebird<MActorFull> {
262 return ActorModel.scope(ScopeNames.FULL).findByPk(id)
263 }
264
265 static loadFromAccountByVideoId (videoId: number, transaction: Sequelize.Transaction): Bluebird<MActor> {
260 const query = { 266 const query = {
261 include: [ 267 include: [
262 { 268 {
@@ -300,7 +306,7 @@ export class ActorModel extends Model<ActorModel> {
300 .then(a => !!a) 306 .then(a => !!a)
301 } 307 }
302 308
303 static listByFollowersUrls (followersUrls: string[], transaction?: Sequelize.Transaction) { 309 static listByFollowersUrls (followersUrls: string[], transaction?: Sequelize.Transaction): Bluebird<MActorFull[]> {
304 const query = { 310 const query = {
305 where: { 311 where: {
306 followersUrl: { 312 followersUrl: {
@@ -313,7 +319,7 @@ export class ActorModel extends Model<ActorModel> {
313 return ActorModel.scope(ScopeNames.FULL).findAll(query) 319 return ActorModel.scope(ScopeNames.FULL).findAll(query)
314 } 320 }
315 321
316 static loadLocalByName (preferredUsername: string, transaction?: Sequelize.Transaction) { 322 static loadLocalByName (preferredUsername: string, transaction?: Sequelize.Transaction): Bluebird<MActorFull> {
317 const query = { 323 const query = {
318 where: { 324 where: {
319 preferredUsername, 325 preferredUsername,
@@ -325,7 +331,7 @@ export class ActorModel extends Model<ActorModel> {
325 return ActorModel.scope(ScopeNames.FULL).findOne(query) 331 return ActorModel.scope(ScopeNames.FULL).findOne(query)
326 } 332 }
327 333
328 static loadByNameAndHost (preferredUsername: string, host: string) { 334 static loadByNameAndHost (preferredUsername: string, host: string): Bluebird<MActorFull> {
329 const query = { 335 const query = {
330 where: { 336 where: {
331 preferredUsername 337 preferredUsername
@@ -344,7 +350,7 @@ export class ActorModel extends Model<ActorModel> {
344 return ActorModel.scope(ScopeNames.FULL).findOne(query) 350 return ActorModel.scope(ScopeNames.FULL).findOne(query)
345 } 351 }
346 352
347 static loadByUrl (url: string, transaction?: Sequelize.Transaction) { 353 static loadByUrl (url: string, transaction?: Sequelize.Transaction): Bluebird<MActorAccountChannelId> {
348 const query = { 354 const query = {
349 where: { 355 where: {
350 url 356 url
@@ -367,7 +373,7 @@ export class ActorModel extends Model<ActorModel> {
367 return ActorModel.unscoped().findOne(query) 373 return ActorModel.unscoped().findOne(query)
368 } 374 }
369 375
370 static loadByUrlAndPopulateAccountAndChannel (url: string, transaction?: Sequelize.Transaction) { 376 static loadByUrlAndPopulateAccountAndChannel (url: string, transaction?: Sequelize.Transaction): Bluebird<MActorFull> {
371 const query = { 377 const query = {
372 where: { 378 where: {
373 url 379 url
diff --git a/server/models/oauth/oauth-token.ts b/server/models/oauth/oauth-token.ts
index 903d551df..b680be237 100644
--- a/server/models/oauth/oauth-token.ts
+++ b/server/models/oauth/oauth-token.ts
@@ -18,6 +18,8 @@ import { Transaction } from 'sequelize'
18import { AccountModel } from '../account/account' 18import { AccountModel } from '../account/account'
19import { ActorModel } from '../activitypub/actor' 19import { ActorModel } from '../activitypub/actor'
20import { clearCacheByToken } from '../../lib/oauth-model' 20import { clearCacheByToken } from '../../lib/oauth-model'
21import * as Bluebird from 'bluebird'
22import { MOAuthTokenUser } from '@server/typings/models/oauth/oauth-token'
21 23
22export type OAuthTokenInfo = { 24export type OAuthTokenInfo = {
23 refreshToken: string 25 refreshToken: string
@@ -160,7 +162,7 @@ export class OAuthTokenModel extends Model<OAuthTokenModel> {
160 }) 162 })
161 } 163 }
162 164
163 static getByTokenAndPopulateUser (bearerToken: string) { 165 static getByTokenAndPopulateUser (bearerToken: string): Bluebird<MOAuthTokenUser> {
164 const query = { 166 const query = {
165 where: { 167 where: {
166 accessToken: bearerToken 168 accessToken: bearerToken
@@ -170,13 +172,13 @@ export class OAuthTokenModel extends Model<OAuthTokenModel> {
170 return OAuthTokenModel.scope(ScopeNames.WITH_USER) 172 return OAuthTokenModel.scope(ScopeNames.WITH_USER)
171 .findOne(query) 173 .findOne(query)
172 .then(token => { 174 .then(token => {
173 if (token) token[ 'user' ] = token.User 175 if (!token) return null
174 176
175 return token 177 return Object.assign(token, { user: token.User })
176 }) 178 })
177 } 179 }
178 180
179 static getByRefreshTokenAndPopulateUser (refreshToken: string) { 181 static getByRefreshTokenAndPopulateUser (refreshToken: string): Bluebird<MOAuthTokenUser> {
180 const query = { 182 const query = {
181 where: { 183 where: {
182 refreshToken: refreshToken 184 refreshToken: refreshToken
@@ -186,12 +188,9 @@ export class OAuthTokenModel extends Model<OAuthTokenModel> {
186 return OAuthTokenModel.scope(ScopeNames.WITH_USER) 188 return OAuthTokenModel.scope(ScopeNames.WITH_USER)
187 .findOne(query) 189 .findOne(query)
188 .then(token => { 190 .then(token => {
189 if (token) { 191 if (!token) return new OAuthTokenModel()
190 token['user'] = token.User 192
191 return token 193 return Object.assign(token, { user: token.User })
192 } else {
193 return new OAuthTokenModel()
194 }
195 }) 194 })
196 } 195 }
197 196
diff --git a/server/models/redundancy/video-redundancy.ts b/server/models/redundancy/video-redundancy.ts
index 3df1c4f9c..1c216b300 100644
--- a/server/models/redundancy/video-redundancy.ts
+++ b/server/models/redundancy/video-redundancy.ts
@@ -30,6 +30,7 @@ import * as Bluebird from 'bluebird'
30import { col, FindOptions, fn, literal, Op, Transaction } from 'sequelize' 30import { col, FindOptions, fn, literal, Op, Transaction } from 'sequelize'
31import { VideoStreamingPlaylistModel } from '../video/video-streaming-playlist' 31import { VideoStreamingPlaylistModel } from '../video/video-streaming-playlist'
32import { CONFIG } from '../../initializers/config' 32import { CONFIG } from '../../initializers/config'
33import { MVideoRedundancy, MVideoRedundancyVideo } from '@server/typings/models'
33 34
34export enum ScopeNames { 35export enum ScopeNames {
35 WITH_VIDEO = 'WITH_VIDEO' 36 WITH_VIDEO = 'WITH_VIDEO'
@@ -166,7 +167,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> {
166 return undefined 167 return undefined
167 } 168 }
168 169
169 static async loadLocalByFileId (videoFileId: number) { 170 static async loadLocalByFileId (videoFileId: number): Promise<MVideoRedundancyVideo> {
170 const actor = await getServerActor() 171 const actor = await getServerActor()
171 172
172 const query = { 173 const query = {
@@ -179,7 +180,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> {
179 return VideoRedundancyModel.scope(ScopeNames.WITH_VIDEO).findOne(query) 180 return VideoRedundancyModel.scope(ScopeNames.WITH_VIDEO).findOne(query)
180 } 181 }
181 182
182 static async loadLocalByStreamingPlaylistId (videoStreamingPlaylistId: number) { 183 static async loadLocalByStreamingPlaylistId (videoStreamingPlaylistId: number): Promise<MVideoRedundancyVideo> {
183 const actor = await getServerActor() 184 const actor = await getServerActor()
184 185
185 const query = { 186 const query = {
@@ -192,7 +193,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> {
192 return VideoRedundancyModel.scope(ScopeNames.WITH_VIDEO).findOne(query) 193 return VideoRedundancyModel.scope(ScopeNames.WITH_VIDEO).findOne(query)
193 } 194 }
194 195
195 static loadByUrl (url: string, transaction?: Transaction) { 196 static loadByUrl (url: string, transaction?: Transaction): Bluebird<MVideoRedundancy> {
196 const query = { 197 const query = {
197 where: { 198 where: {
198 url 199 url
@@ -306,7 +307,7 @@ export class VideoRedundancyModel extends Model<VideoRedundancyModel> {
306 return VideoRedundancyModel.getVideoSample(VideoModel.unscoped().findAll(query)) 307 return VideoRedundancyModel.getVideoSample(VideoModel.unscoped().findAll(query))
307 } 308 }
308 309
309 static async loadOldestLocalThatAlreadyExpired (strategy: VideoRedundancyStrategy, expiresAfterMs: number) { 310 static async loadOldestLocalExpired (strategy: VideoRedundancyStrategy, expiresAfterMs: number): Promise<MVideoRedundancyVideo> {
310 const expiredDate = new Date() 311 const expiredDate = new Date()
311 expiredDate.setMilliseconds(expiredDate.getMilliseconds() - expiresAfterMs) 312 expiredDate.setMilliseconds(expiredDate.getMilliseconds() - expiresAfterMs)
312 313
diff --git a/server/models/server/plugin.ts b/server/models/server/plugin.ts
index a15f9a7e2..debd25ea1 100644
--- a/server/models/server/plugin.ts
+++ b/server/models/server/plugin.ts
@@ -11,6 +11,8 @@ import { PluginType } from '../../../shared/models/plugins/plugin.type'
11import { PeerTubePlugin } from '../../../shared/models/plugins/peertube-plugin.model' 11import { PeerTubePlugin } from '../../../shared/models/plugins/peertube-plugin.model'
12import { FindAndCountOptions, json } from 'sequelize' 12import { FindAndCountOptions, json } from 'sequelize'
13import { RegisterServerSettingOptions } from '../../../shared/models/plugins/register-server-setting.model' 13import { RegisterServerSettingOptions } from '../../../shared/models/plugins/register-server-setting.model'
14import * as Bluebird from 'bluebird'
15import { MPlugin } from '@server/typings/models'
14 16
15@DefaultScope(() => ({ 17@DefaultScope(() => ({
16 attributes: { 18 attributes: {
@@ -85,7 +87,7 @@ export class PluginModel extends Model<PluginModel> {
85 @UpdatedAt 87 @UpdatedAt
86 updatedAt: Date 88 updatedAt: Date
87 89
88 static listEnabledPluginsAndThemes () { 90 static listEnabledPluginsAndThemes (): Bluebird<MPlugin[]> {
89 const query = { 91 const query = {
90 where: { 92 where: {
91 enabled: true, 93 enabled: true,
@@ -96,7 +98,7 @@ export class PluginModel extends Model<PluginModel> {
96 return PluginModel.findAll(query) 98 return PluginModel.findAll(query)
97 } 99 }
98 100
99 static loadByNpmName (npmName: string) { 101 static loadByNpmName (npmName: string): Bluebird<MPlugin> {
100 const name = this.normalizePluginName(npmName) 102 const name = this.normalizePluginName(npmName)
101 const type = this.getTypeFromNpmName(npmName) 103 const type = this.getTypeFromNpmName(npmName)
102 104
@@ -206,13 +208,13 @@ export class PluginModel extends Model<PluginModel> {
206 if (options.pluginType) query.where['type'] = options.pluginType 208 if (options.pluginType) query.where['type'] = options.pluginType
207 209
208 return PluginModel 210 return PluginModel
209 .findAndCountAll(query) 211 .findAndCountAll<MPlugin>(query)
210 .then(({ rows, count }) => { 212 .then(({ rows, count }) => {
211 return { total: count, data: rows } 213 return { total: count, data: rows }
212 }) 214 })
213 } 215 }
214 216
215 static listInstalled () { 217 static listInstalled (): Bluebird<MPlugin[]> {
216 const query = { 218 const query = {
217 where: { 219 where: {
218 uninstalled: false 220 uninstalled: false
diff --git a/server/models/server/server-blocklist.ts b/server/models/server/server-blocklist.ts
index 5138b0f76..e4db93dfc 100644
--- a/server/models/server/server-blocklist.ts
+++ b/server/models/server/server-blocklist.ts
@@ -3,6 +3,8 @@ import { AccountModel } from '../account/account'
3import { ServerModel } from './server' 3import { ServerModel } from './server'
4import { ServerBlock } from '../../../shared/models/blocklist' 4import { ServerBlock } from '../../../shared/models/blocklist'
5import { getSort } from '../utils' 5import { getSort } from '../utils'
6import * as Bluebird from 'bluebird'
7import { MServerBlocklist, MServerBlocklistAccountServer } from '@server/typings/models'
6 8
7enum ScopeNames { 9enum ScopeNames {
8 WITH_ACCOUNT = 'WITH_ACCOUNT', 10 WITH_ACCOUNT = 'WITH_ACCOUNT',
@@ -73,7 +75,7 @@ export class ServerBlocklistModel extends Model<ServerBlocklistModel> {
73 }) 75 })
74 BlockedServer: ServerModel 76 BlockedServer: ServerModel
75 77
76 static loadByAccountAndHost (accountId: number, host: string) { 78 static loadByAccountAndHost (accountId: number, host: string): Bluebird<MServerBlocklist> {
77 const query = { 79 const query = {
78 where: { 80 where: {
79 accountId 81 accountId
@@ -104,7 +106,7 @@ export class ServerBlocklistModel extends Model<ServerBlocklistModel> {
104 106
105 return ServerBlocklistModel 107 return ServerBlocklistModel
106 .scope([ ScopeNames.WITH_ACCOUNT, ScopeNames.WITH_SERVER ]) 108 .scope([ ScopeNames.WITH_ACCOUNT, ScopeNames.WITH_SERVER ])
107 .findAndCountAll(query) 109 .findAndCountAll<MServerBlocklistAccountServer>(query)
108 .then(({ rows, count }) => { 110 .then(({ rows, count }) => {
109 return { total: count, data: rows } 111 return { total: count, data: rows }
110 }) 112 })
diff --git a/server/models/server/server.ts b/server/models/server/server.ts
index 1d211f1e0..b0bdd2b0b 100644
--- a/server/models/server/server.ts
+++ b/server/models/server/server.ts
@@ -2,8 +2,9 @@ import { AllowNull, Column, CreatedAt, Default, HasMany, Is, Model, Table, Updat
2import { isHostValid } from '../../helpers/custom-validators/servers' 2import { isHostValid } from '../../helpers/custom-validators/servers'
3import { ActorModel } from '../activitypub/actor' 3import { ActorModel } from '../activitypub/actor'
4import { throwIfNotValid } from '../utils' 4import { throwIfNotValid } from '../utils'
5import { AccountBlocklistModel } from '../account/account-blocklist'
6import { ServerBlocklistModel } from './server-blocklist' 5import { ServerBlocklistModel } from './server-blocklist'
6import * as Bluebird from 'bluebird'
7import { MServer } from '@server/typings/models/server'
7 8
8@Table({ 9@Table({
9 tableName: 'server', 10 tableName: 'server',
@@ -50,7 +51,7 @@ export class ServerModel extends Model<ServerModel> {
50 }) 51 })
51 BlockedByAccounts: ServerBlocklistModel[] 52 BlockedByAccounts: ServerBlocklistModel[]
52 53
53 static loadByHost (host: string) { 54 static loadByHost (host: string): Bluebird<MServer> {
54 const query = { 55 const query = {
55 where: { 56 where: {
56 host 57 host
diff --git a/server/models/video/video-abuse.ts b/server/models/video/video-abuse.ts
index 1ac7919b3..af7b40d11 100644
--- a/server/models/video/video-abuse.ts
+++ b/server/models/video/video-abuse.ts
@@ -11,6 +11,8 @@ import { getSort, throwIfNotValid } from '../utils'
11import { VideoModel } from './video' 11import { VideoModel } from './video'
12import { VideoAbuseState } from '../../../shared' 12import { VideoAbuseState } from '../../../shared'
13import { CONSTRAINTS_FIELDS, VIDEO_ABUSE_STATES } from '../../initializers/constants' 13import { CONSTRAINTS_FIELDS, VIDEO_ABUSE_STATES } from '../../initializers/constants'
14import { MVideoAbuse, MVideoAbuseAccountVideo, MVideoAbuseVideo } from '../../typings/models'
15import * as Bluebird from 'bluebird'
14 16
15@Table({ 17@Table({
16 tableName: 'videoAbuse', 18 tableName: 'videoAbuse',
@@ -73,7 +75,7 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> {
73 }) 75 })
74 Video: VideoModel 76 Video: VideoModel
75 77
76 static loadByIdAndVideoId (id: number, videoId: number) { 78 static loadByIdAndVideoId (id: number, videoId: number): Bluebird<MVideoAbuse> {
77 const query = { 79 const query = {
78 where: { 80 where: {
79 id, 81 id,
@@ -106,7 +108,7 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> {
106 }) 108 })
107 } 109 }
108 110
109 toFormattedJSON (): VideoAbuse { 111 toFormattedJSON (this: MVideoAbuseAccountVideo): VideoAbuse {
110 return { 112 return {
111 id: this.id, 113 id: this.id,
112 reason: this.reason, 114 reason: this.reason,
@@ -125,7 +127,7 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> {
125 } 127 }
126 } 128 }
127 129
128 toActivityPubObject (): VideoAbuseObject { 130 toActivityPubObject (this: MVideoAbuseVideo): VideoAbuseObject {
129 return { 131 return {
130 type: 'Flag' as 'Flag', 132 type: 'Flag' as 'Flag',
131 content: this.reason, 133 content: this.reason,
diff --git a/server/models/video/video-blacklist.ts b/server/models/video/video-blacklist.ts
index 22d949da0..5a0cac94a 100644
--- a/server/models/video/video-blacklist.ts
+++ b/server/models/video/video-blacklist.ts
@@ -1,12 +1,14 @@
1import { AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' 1import { AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, Is, Model, Table, UpdatedAt } from 'sequelize-typescript'
2import { getSortOnModel, SortType, throwIfNotValid } from '../utils' 2import { getSortOnModel, SortType, throwIfNotValid } from '../utils'
3import { ScopeNames as VideoModelScopeNames, VideoModel } from './video' 3import { VideoModel } from './video'
4import { ScopeNames as VideoChannelScopeNames, SummaryOptions, VideoChannelModel } from './video-channel' 4import { ScopeNames as VideoChannelScopeNames, SummaryOptions, VideoChannelModel } from './video-channel'
5import { isVideoBlacklistReasonValid, isVideoBlacklistTypeValid } from '../../helpers/custom-validators/video-blacklist' 5import { isVideoBlacklistReasonValid, isVideoBlacklistTypeValid } from '../../helpers/custom-validators/video-blacklist'
6import { VideoBlacklist, VideoBlacklistType } from '../../../shared/models/videos' 6import { VideoBlacklist, VideoBlacklistType } from '../../../shared/models/videos'
7import { CONSTRAINTS_FIELDS } from '../../initializers/constants' 7import { CONSTRAINTS_FIELDS } from '../../initializers/constants'
8import { FindOptions } from 'sequelize' 8import { FindOptions } from 'sequelize'
9import { ThumbnailModel } from './thumbnail' 9import { ThumbnailModel } from './thumbnail'
10import * as Bluebird from 'bluebird'
11import { MVideoBlacklist } from '@server/typings/models'
10 12
11@Table({ 13@Table({
12 tableName: 'videoBlacklist', 14 tableName: 'videoBlacklist',
@@ -99,7 +101,7 @@ export class VideoBlacklistModel extends Model<VideoBlacklistModel> {
99 }) 101 })
100 } 102 }
101 103
102 static loadByVideoId (id: number) { 104 static loadByVideoId (id: number): Bluebird<MVideoBlacklist> {
103 const query = { 105 const query = {
104 where: { 106 where: {
105 videoId: id 107 videoId: id
diff --git a/server/models/video/video-caption.ts b/server/models/video/video-caption.ts
index a01565851..9ce350d12 100644
--- a/server/models/video/video-caption.ts
+++ b/server/models/video/video-caption.ts
@@ -21,6 +21,8 @@ import { join } from 'path'
21import { logger } from '../../helpers/logger' 21import { logger } from '../../helpers/logger'
22import { remove } from 'fs-extra' 22import { remove } from 'fs-extra'
23import { CONFIG } from '../../initializers/config' 23import { CONFIG } from '../../initializers/config'
24import * as Bluebird from 'bluebird'
25import { MVideoCaptionVideo } from '@server/typings/models'
24 26
25export enum ScopeNames { 27export enum ScopeNames {
26 WITH_VIDEO_UUID_AND_REMOTE = 'WITH_VIDEO_UUID_AND_REMOTE' 28 WITH_VIDEO_UUID_AND_REMOTE = 'WITH_VIDEO_UUID_AND_REMOTE'
@@ -30,7 +32,7 @@ export enum ScopeNames {
30 [ScopeNames.WITH_VIDEO_UUID_AND_REMOTE]: { 32 [ScopeNames.WITH_VIDEO_UUID_AND_REMOTE]: {
31 include: [ 33 include: [
32 { 34 {
33 attributes: [ 'uuid', 'remote' ], 35 attributes: [ 'id', 'uuid', 'remote' ],
34 model: VideoModel.unscoped(), 36 model: VideoModel.unscoped(),
35 required: true 37 required: true
36 } 38 }
@@ -93,7 +95,7 @@ export class VideoCaptionModel extends Model<VideoCaptionModel> {
93 return undefined 95 return undefined
94 } 96 }
95 97
96 static loadByVideoIdAndLanguage (videoId: string | number, language: string) { 98 static loadByVideoIdAndLanguage (videoId: string | number, language: string): Bluebird<MVideoCaptionVideo> {
97 const videoInclude = { 99 const videoInclude = {
98 model: VideoModel.unscoped(), 100 model: VideoModel.unscoped(),
99 attributes: [ 'id', 'remote', 'uuid' ], 101 attributes: [ 'id', 'remote', 'uuid' ],
@@ -122,7 +124,7 @@ export class VideoCaptionModel extends Model<VideoCaptionModel> {
122 .then(([ caption ]) => caption) 124 .then(([ caption ]) => caption)
123 } 125 }
124 126
125 static listVideoCaptions (videoId: number) { 127 static listVideoCaptions (videoId: number): Bluebird<MVideoCaptionVideo[]> {
126 const query = { 128 const query = {
127 order: [ [ 'language', 'ASC' ] ] as OrderItem[], 129 order: [ [ 'language', 'ASC' ] ] as OrderItem[],
128 where: { 130 where: {
diff --git a/server/models/video/video-change-ownership.ts b/server/models/video/video-change-ownership.ts
index b545a2f8c..2d0ff48fb 100644
--- a/server/models/video/video-change-ownership.ts
+++ b/server/models/video/video-change-ownership.ts
@@ -3,6 +3,8 @@ import { AccountModel } from '../account/account'
3import { ScopeNames as VideoScopeNames, VideoModel } from './video' 3import { ScopeNames as VideoScopeNames, VideoModel } from './video'
4import { VideoChangeOwnership, VideoChangeOwnershipStatus } from '../../../shared/models/videos' 4import { VideoChangeOwnership, VideoChangeOwnershipStatus } from '../../../shared/models/videos'
5import { getSort } from '../utils' 5import { getSort } from '../utils'
6import { MVideoChangeOwnershipFull } from '@server/typings/models/video/video-change-ownership'
7import * as Bluebird from 'bluebird'
6 8
7enum ScopeNames { 9enum ScopeNames {
8 WITH_ACCOUNTS = 'WITH_ACCOUNTS', 10 WITH_ACCOUNTS = 'WITH_ACCOUNTS',
@@ -108,11 +110,11 @@ export class VideoChangeOwnershipModel extends Model<VideoChangeOwnershipModel>
108 110
109 return Promise.all([ 111 return Promise.all([
110 VideoChangeOwnershipModel.scope(ScopeNames.WITH_ACCOUNTS).count(query), 112 VideoChangeOwnershipModel.scope(ScopeNames.WITH_ACCOUNTS).count(query),
111 VideoChangeOwnershipModel.scope([ ScopeNames.WITH_ACCOUNTS, ScopeNames.WITH_VIDEO ]).findAll(query) 113 VideoChangeOwnershipModel.scope([ ScopeNames.WITH_ACCOUNTS, ScopeNames.WITH_VIDEO ]).findAll<MVideoChangeOwnershipFull>(query)
112 ]).then(([ count, rows ]) => ({ total: count, data: rows })) 114 ]).then(([ count, rows ]) => ({ total: count, data: rows }))
113 } 115 }
114 116
115 static load (id: number) { 117 static load (id: number): Bluebird<MVideoChangeOwnershipFull> {
116 return VideoChangeOwnershipModel.scope([ ScopeNames.WITH_ACCOUNTS, ScopeNames.WITH_VIDEO ]) 118 return VideoChangeOwnershipModel.scope([ ScopeNames.WITH_ACCOUNTS, ScopeNames.WITH_VIDEO ])
117 .findByPk(id) 119 .findByPk(id)
118 } 120 }
diff --git a/server/models/video/video-channel.ts b/server/models/video/video-channel.ts
index 6241a75a3..79b9e7d2b 100644
--- a/server/models/video/video-channel.ts
+++ b/server/models/video/video-channel.ts
@@ -33,6 +33,13 @@ import { ServerModel } from '../server/server'
33import { FindOptions, ModelIndexesOptions, Op } from 'sequelize' 33import { FindOptions, ModelIndexesOptions, Op } from 'sequelize'
34import { AvatarModel } from '../avatar/avatar' 34import { AvatarModel } from '../avatar/avatar'
35import { VideoPlaylistModel } from './video-playlist' 35import { VideoPlaylistModel } from './video-playlist'
36import * as Bluebird from 'bluebird'
37import {
38 MChannelAccountDefault,
39 MChannelActor,
40 MChannelActorAccountDefault,
41 MChannelActorAccountDefaultVideos
42} from '../../typings/models/video'
36 43
37// FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation 44// FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation
38const indexes: ModelIndexesOptions[] = [ 45const indexes: ModelIndexesOptions[] = [
@@ -47,7 +54,7 @@ const indexes: ModelIndexesOptions[] = [
47] 54]
48 55
49export enum ScopeNames { 56export enum ScopeNames {
50 AVAILABLE_FOR_LIST = 'AVAILABLE_FOR_LIST', 57 FOR_API = 'FOR_API',
51 WITH_ACCOUNT = 'WITH_ACCOUNT', 58 WITH_ACCOUNT = 'WITH_ACCOUNT',
52 WITH_ACTOR = 'WITH_ACTOR', 59 WITH_ACTOR = 'WITH_ACTOR',
53 WITH_VIDEOS = 'WITH_VIDEOS', 60 WITH_VIDEOS = 'WITH_VIDEOS',
@@ -74,10 +81,10 @@ export type SummaryOptions = {
74@Scopes(() => ({ 81@Scopes(() => ({
75 [ScopeNames.SUMMARY]: (options: SummaryOptions = {}) => { 82 [ScopeNames.SUMMARY]: (options: SummaryOptions = {}) => {
76 const base: FindOptions = { 83 const base: FindOptions = {
77 attributes: [ 'name', 'description', 'id', 'actorId' ], 84 attributes: [ 'id', 'name', 'description', 'actorId' ],
78 include: [ 85 include: [
79 { 86 {
80 attributes: [ 'preferredUsername', 'url', 'serverId', 'avatarId' ], 87 attributes: [ 'id', 'preferredUsername', 'url', 'serverId', 'avatarId' ],
81 model: ActorModel.unscoped(), 88 model: ActorModel.unscoped(),
82 required: true, 89 required: true,
83 include: [ 90 include: [
@@ -106,7 +113,7 @@ export type SummaryOptions = {
106 113
107 return base 114 return base
108 }, 115 },
109 [ScopeNames.AVAILABLE_FOR_LIST]: (options: AvailableForListOptions) => { 116 [ScopeNames.FOR_API]: (options: AvailableForListOptions) => {
110 // Only list local channels OR channels that are on an instance followed by actorId 117 // Only list local channels OR channels that are on an instance followed by actorId
111 const inQueryInstanceFollow = buildServerIdsFollowedBy(options.actorId) 118 const inQueryInstanceFollow = buildServerIdsFollowedBy(options.actorId)
112 119
@@ -268,7 +275,7 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
268 } 275 }
269 276
270 const scopes = { 277 const scopes = {
271 method: [ ScopeNames.AVAILABLE_FOR_LIST, { actorId } as AvailableForListOptions ] 278 method: [ ScopeNames.FOR_API, { actorId } as AvailableForListOptions ]
272 } 279 }
273 return VideoChannelModel 280 return VideoChannelModel
274 .scope(scopes) 281 .scope(scopes)
@@ -278,7 +285,7 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
278 }) 285 })
279 } 286 }
280 287
281 static listLocalsForSitemap (sort: string) { 288 static listLocalsForSitemap (sort: string): Bluebird<MChannelActor[]> {
282 const query = { 289 const query = {
283 attributes: [ ], 290 attributes: [ ],
284 offset: 0, 291 offset: 0,
@@ -331,7 +338,7 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
331 } 338 }
332 339
333 const scopes = { 340 const scopes = {
334 method: [ ScopeNames.AVAILABLE_FOR_LIST, { actorId: options.actorId } as AvailableForListOptions ] 341 method: [ ScopeNames.FOR_API, { actorId: options.actorId } as AvailableForListOptions ]
335 } 342 }
336 return VideoChannelModel 343 return VideoChannelModel
337 .scope(scopes) 344 .scope(scopes)
@@ -369,13 +376,13 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
369 }) 376 })
370 } 377 }
371 378
372 static loadByIdAndPopulateAccount (id: number) { 379 static loadByIdAndPopulateAccount (id: number): Bluebird<MChannelActorAccountDefault> {
373 return VideoChannelModel.unscoped() 380 return VideoChannelModel.unscoped()
374 .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ]) 381 .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ])
375 .findByPk(id) 382 .findByPk(id)
376 } 383 }
377 384
378 static loadByIdAndAccount (id: number, accountId: number) { 385 static loadByIdAndAccount (id: number, accountId: number): Bluebird<MChannelActorAccountDefault> {
379 const query = { 386 const query = {
380 where: { 387 where: {
381 id, 388 id,
@@ -388,13 +395,13 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
388 .findOne(query) 395 .findOne(query)
389 } 396 }
390 397
391 static loadAndPopulateAccount (id: number) { 398 static loadAndPopulateAccount (id: number): Bluebird<MChannelActorAccountDefault> {
392 return VideoChannelModel.unscoped() 399 return VideoChannelModel.unscoped()
393 .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ]) 400 .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ])
394 .findByPk(id) 401 .findByPk(id)
395 } 402 }
396 403
397 static loadByUrlAndPopulateAccount (url: string) { 404 static loadByUrlAndPopulateAccount (url: string): Bluebird<MChannelAccountDefault> {
398 const query = { 405 const query = {
399 include: [ 406 include: [
400 { 407 {
@@ -420,7 +427,7 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
420 return VideoChannelModel.loadByNameAndHostAndPopulateAccount(name, host) 427 return VideoChannelModel.loadByNameAndHostAndPopulateAccount(name, host)
421 } 428 }
422 429
423 static loadLocalByNameAndPopulateAccount (name: string) { 430 static loadLocalByNameAndPopulateAccount (name: string): Bluebird<MChannelActorAccountDefault> {
424 const query = { 431 const query = {
425 include: [ 432 include: [
426 { 433 {
@@ -439,7 +446,7 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
439 .findOne(query) 446 .findOne(query)
440 } 447 }
441 448
442 static loadByNameAndHostAndPopulateAccount (name: string, host: string) { 449 static loadByNameAndHostAndPopulateAccount (name: string, host: string): Bluebird<MChannelActorAccountDefault> {
443 const query = { 450 const query = {
444 include: [ 451 include: [
445 { 452 {
@@ -464,7 +471,7 @@ export class VideoChannelModel extends Model<VideoChannelModel> {
464 .findOne(query) 471 .findOne(query)
465 } 472 }
466 473
467 static loadAndPopulateAccountAndVideos (id: number) { 474 static loadAndPopulateAccountAndVideos (id: number): Bluebird<MChannelActorAccountDefaultVideos> {
468 const options = { 475 const options = {
469 include: [ 476 include: [
470 VideoModel 477 VideoModel
diff --git a/server/models/video/video-comment.ts b/server/models/video/video-comment.ts
index 58b75510d..c88dac1c1 100644
--- a/server/models/video/video-comment.ts
+++ b/server/models/video/video-comment.ts
@@ -1,36 +1,30 @@
1import { 1import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, Is, Model, Scopes, Table, UpdatedAt } from 'sequelize-typescript'
2 AllowNull,
3 BeforeDestroy,
4 BelongsTo,
5 Column,
6 CreatedAt,
7 DataType,
8 ForeignKey,
9 Is,
10 Model,
11 Scopes,
12 Table,
13 UpdatedAt
14} from 'sequelize-typescript'
15import { ActivityTagObject } from '../../../shared/models/activitypub/objects/common-objects' 2import { ActivityTagObject } from '../../../shared/models/activitypub/objects/common-objects'
16import { VideoCommentObject } from '../../../shared/models/activitypub/objects/video-comment-object' 3import { VideoCommentObject } from '../../../shared/models/activitypub/objects/video-comment-object'
17import { VideoComment } from '../../../shared/models/videos/video-comment.model' 4import { VideoComment } from '../../../shared/models/videos/video-comment.model'
18import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' 5import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
19import { CONSTRAINTS_FIELDS, WEBSERVER } from '../../initializers/constants' 6import { CONSTRAINTS_FIELDS, WEBSERVER } from '../../initializers/constants'
20import { sendDeleteVideoComment } from '../../lib/activitypub/send'
21import { AccountModel } from '../account/account' 7import { AccountModel } from '../account/account'
22import { ActorModel } from '../activitypub/actor' 8import { ActorModel } from '../activitypub/actor'
23import { AvatarModel } from '../avatar/avatar'
24import { ServerModel } from '../server/server'
25import { buildBlockedAccountSQL, buildLocalAccountIdsIn, getSort, throwIfNotValid } from '../utils' 9import { buildBlockedAccountSQL, buildLocalAccountIdsIn, getSort, throwIfNotValid } from '../utils'
26import { VideoModel } from './video' 10import { VideoModel } from './video'
27import { VideoChannelModel } from './video-channel' 11import { VideoChannelModel } from './video-channel'
28import { getServerActor } from '../../helpers/utils' 12import { getServerActor } from '../../helpers/utils'
29import { UserModel } from '../account/user'
30import { actorNameAlphabet } from '../../helpers/custom-validators/activitypub/actor' 13import { actorNameAlphabet } from '../../helpers/custom-validators/activitypub/actor'
31import { regexpCapture } from '../../helpers/regexp' 14import { regexpCapture } from '../../helpers/regexp'
32import { uniq } from 'lodash' 15import { uniq } from 'lodash'
33import { FindOptions, literal, Op, Order, ScopeOptions, Sequelize, Transaction } from 'sequelize' 16import { FindOptions, Op, Order, ScopeOptions, Sequelize, Transaction } from 'sequelize'
17import * as Bluebird from 'bluebird'
18import {
19 MComment,
20 MCommentId,
21 MCommentOwner,
22 MCommentOwnerReplyVideoLight,
23 MCommentOwnerVideo,
24 MCommentOwnerVideoFeed,
25 MCommentOwnerVideoReply
26} from '../../typings/models/video'
27import { MUserAccountId } from '@server/typings/models'
34 28
35enum ScopeNames { 29enum ScopeNames {
36 WITH_ACCOUNT = 'WITH_ACCOUNT', 30 WITH_ACCOUNT = 'WITH_ACCOUNT',
@@ -68,22 +62,7 @@ enum ScopeNames {
68 [ScopeNames.WITH_ACCOUNT]: { 62 [ScopeNames.WITH_ACCOUNT]: {
69 include: [ 63 include: [
70 { 64 {
71 model: AccountModel, 65 model: AccountModel
72 include: [
73 {
74 model: ActorModel,
75 include: [
76 {
77 model: ServerModel,
78 required: false
79 },
80 {
81 model: AvatarModel,
82 required: false
83 }
84 ]
85 }
86 ]
87 } 66 }
88 ] 67 ]
89 }, 68 },
@@ -102,22 +81,12 @@ enum ScopeNames {
102 required: true, 81 required: true,
103 include: [ 82 include: [
104 { 83 {
105 model: VideoChannelModel.unscoped(), 84 model: VideoChannelModel,
106 required: true, 85 required: true,
107 include: [ 86 include: [
108 { 87 {
109 model: ActorModel,
110 required: true
111 },
112 {
113 model: AccountModel, 88 model: AccountModel,
114 required: true, 89 required: true
115 include: [
116 {
117 model: ActorModel,
118 required: true
119 }
120 ]
121 } 90 }
122 ] 91 ]
123 } 92 }
@@ -212,7 +181,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
212 }) 181 })
213 Account: AccountModel 182 Account: AccountModel
214 183
215 static loadById (id: number, t?: Transaction) { 184 static loadById (id: number, t?: Transaction): Bluebird<MComment> {
216 const query: FindOptions = { 185 const query: FindOptions = {
217 where: { 186 where: {
218 id 187 id
@@ -224,7 +193,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
224 return VideoCommentModel.findOne(query) 193 return VideoCommentModel.findOne(query)
225 } 194 }
226 195
227 static loadByIdAndPopulateVideoAndAccountAndReply (id: number, t?: Transaction) { 196 static loadByIdAndPopulateVideoAndAccountAndReply (id: number, t?: Transaction): Bluebird<MCommentOwnerVideoReply> {
228 const query: FindOptions = { 197 const query: FindOptions = {
229 where: { 198 where: {
230 id 199 id
@@ -238,7 +207,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
238 .findOne(query) 207 .findOne(query)
239 } 208 }
240 209
241 static loadByUrlAndPopulateAccountAndVideo (url: string, t?: Transaction) { 210 static loadByUrlAndPopulateAccountAndVideo (url: string, t?: Transaction): Bluebird<MCommentOwnerVideo> {
242 const query: FindOptions = { 211 const query: FindOptions = {
243 where: { 212 where: {
244 url 213 url
@@ -250,7 +219,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
250 return VideoCommentModel.scope([ ScopeNames.WITH_ACCOUNT, ScopeNames.WITH_VIDEO ]).findOne(query) 219 return VideoCommentModel.scope([ ScopeNames.WITH_ACCOUNT, ScopeNames.WITH_VIDEO ]).findOne(query)
251 } 220 }
252 221
253 static loadByUrlAndPopulateReplyAndVideoUrlAndAccount (url: string, t?: Transaction) { 222 static loadByUrlAndPopulateReplyAndVideoUrlAndAccount (url: string, t?: Transaction): Bluebird<MCommentOwnerReplyVideoLight> {
254 const query: FindOptions = { 223 const query: FindOptions = {
255 where: { 224 where: {
256 url 225 url
@@ -273,7 +242,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
273 start: number, 242 start: number,
274 count: number, 243 count: number,
275 sort: string, 244 sort: string,
276 user?: UserModel 245 user?: MUserAccountId
277 }) { 246 }) {
278 const { videoId, start, count, sort, user } = parameters 247 const { videoId, start, count, sort, user } = parameters
279 248
@@ -314,7 +283,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
314 static async listThreadCommentsForApi (parameters: { 283 static async listThreadCommentsForApi (parameters: {
315 videoId: number, 284 videoId: number,
316 threadId: number, 285 threadId: number,
317 user?: UserModel 286 user?: MUserAccountId
318 }) { 287 }) {
319 const { videoId, threadId, user } = parameters 288 const { videoId, threadId, user } = parameters
320 289
@@ -353,7 +322,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
353 }) 322 })
354 } 323 }
355 324
356 static listThreadParentComments (comment: VideoCommentModel, t: Transaction, order: 'ASC' | 'DESC' = 'ASC') { 325 static listThreadParentComments (comment: MCommentId, t: Transaction, order: 'ASC' | 'DESC' = 'ASC'): Bluebird<MCommentOwner[]> {
357 const query = { 326 const query = {
358 order: [ [ 'createdAt', order ] ] as Order, 327 order: [ [ 'createdAt', order ] ] as Order,
359 where: { 328 where: {
@@ -389,10 +358,10 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
389 transaction: t 358 transaction: t
390 } 359 }
391 360
392 return VideoCommentModel.findAndCountAll(query) 361 return VideoCommentModel.findAndCountAll<MComment>(query)
393 } 362 }
394 363
395 static listForFeed (start: number, count: number, videoId?: number) { 364 static listForFeed (start: number, count: number, videoId?: number): Bluebird<MCommentOwnerVideoFeed[]> {
396 const query = { 365 const query = {
397 order: [ [ 'createdAt', 'DESC' ] ] as Order, 366 order: [ [ 'createdAt', 'DESC' ] ] as Order,
398 offset: start, 367 offset: start,
@@ -521,7 +490,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> {
521 } as VideoComment 490 } as VideoComment
522 } 491 }
523 492
524 toActivityPubObject (threadParentComments: VideoCommentModel[]): VideoCommentObject { 493 toActivityPubObject (threadParentComments: MCommentOwner[]): VideoCommentObject {
525 let inReplyTo: string 494 let inReplyTo: string
526 // New thread, so in AS we reply to the video 495 // New thread, so in AS we reply to the video
527 if (this.inReplyToCommentId === null) { 496 if (this.inReplyToCommentId === null) {
diff --git a/server/models/video/video-file.ts b/server/models/video/video-file.ts
index 05c490759..6304f741c 100644
--- a/server/models/video/video-file.ts
+++ b/server/models/video/video-file.ts
@@ -25,6 +25,7 @@ import { VideoRedundancyModel } from '../redundancy/video-redundancy'
25import { VideoStreamingPlaylistModel } from './video-streaming-playlist' 25import { VideoStreamingPlaylistModel } from './video-streaming-playlist'
26import { FindOptions, QueryTypes, Transaction } from 'sequelize' 26import { FindOptions, QueryTypes, Transaction } from 'sequelize'
27import { MIMETYPES } from '../../initializers/constants' 27import { MIMETYPES } from '../../initializers/constants'
28import { MVideoFile } from '@server/typings/models'
28 29
29@Table({ 30@Table({
30 tableName: 'videoFile', 31 tableName: 'videoFile',
@@ -166,7 +167,7 @@ export class VideoFileModel extends Model<VideoFileModel> {
166 return !!MIMETYPES.AUDIO.EXT_MIMETYPE[this.extname] 167 return !!MIMETYPES.AUDIO.EXT_MIMETYPE[this.extname]
167 } 168 }
168 169
169 hasSameUniqueKeysThan (other: VideoFileModel) { 170 hasSameUniqueKeysThan (other: MVideoFile) {
170 return this.fps === other.fps && 171 return this.fps === other.fps &&
171 this.resolution === other.resolution && 172 this.resolution === other.resolution &&
172 this.videoId === other.videoId 173 this.videoId === other.videoId
diff --git a/server/models/video/video-format-utils.ts b/server/models/video/video-format-utils.ts
index 284539def..4e7eb5f0c 100644
--- a/server/models/video/video-format-utils.ts
+++ b/server/models/video/video-format-utils.ts
@@ -1,6 +1,5 @@
1import { Video, VideoDetails, VideoFile } from '../../../shared/models/videos' 1import { Video, VideoDetails, VideoFile } from '../../../shared/models/videos'
2import { VideoModel } from './video' 2import { VideoModel } from './video'
3import { VideoFileModel } from './video-file'
4import { 3import {
5 ActivityPlaylistInfohashesObject, 4 ActivityPlaylistInfohashesObject,
6 ActivityPlaylistSegmentHashesObject, 5 ActivityPlaylistSegmentHashesObject,
@@ -17,7 +16,9 @@ import {
17} from '../../lib/activitypub' 16} from '../../lib/activitypub'
18import { isArray } from '../../helpers/custom-validators/misc' 17import { isArray } from '../../helpers/custom-validators/misc'
19import { VideoStreamingPlaylist } from '../../../shared/models/videos/video-streaming-playlist.model' 18import { VideoStreamingPlaylist } from '../../../shared/models/videos/video-streaming-playlist.model'
20import { VideoStreamingPlaylistModel } from './video-streaming-playlist' 19import { MVideo, MVideoAP, MVideoDetails } from '../../typings/models'
20import { MStreamingPlaylistRedundancies } from '../../typings/models/video/video-streaming-playlist'
21import { MVideoFileRedundanciesOpt } from '../../typings/models/video/video-file'
21 22
22export type VideoFormattingJSONOptions = { 23export type VideoFormattingJSONOptions = {
23 completeDescription?: boolean 24 completeDescription?: boolean
@@ -102,7 +103,7 @@ function videoModelToFormattedJSON (video: VideoModel, options?: VideoFormatting
102 return videoObject 103 return videoObject
103} 104}
104 105
105function videoModelToFormattedDetailsJSON (video: VideoModel): VideoDetails { 106function videoModelToFormattedDetailsJSON (video: MVideoDetails): VideoDetails {
106 const formattedJson = video.toFormattedJSON({ 107 const formattedJson = video.toFormattedJSON({
107 additionalAttributes: { 108 additionalAttributes: {
108 scheduledUpdate: true, 109 scheduledUpdate: true,
@@ -114,7 +115,7 @@ function videoModelToFormattedDetailsJSON (video: VideoModel): VideoDetails {
114 115
115 const tags = video.Tags ? video.Tags.map(t => t.name) : [] 116 const tags = video.Tags ? video.Tags.map(t => t.name) : []
116 117
117 const streamingPlaylists = streamingPlaylistsModelToFormattedJSON(video, video.VideoStreamingPlaylists) 118 const streamingPlaylists = streamingPlaylistsModelToFormattedJSON(video.VideoStreamingPlaylists)
118 119
119 const detailsJson = { 120 const detailsJson = {
120 support: video.support, 121 support: video.support,
@@ -142,7 +143,7 @@ function videoModelToFormattedDetailsJSON (video: VideoModel): VideoDetails {
142 return Object.assign(formattedJson, detailsJson) 143 return Object.assign(formattedJson, detailsJson)
143} 144}
144 145
145function streamingPlaylistsModelToFormattedJSON (video: VideoModel, playlists: VideoStreamingPlaylistModel[]): VideoStreamingPlaylist[] { 146function streamingPlaylistsModelToFormattedJSON (playlists: MStreamingPlaylistRedundancies[]): VideoStreamingPlaylist[] {
146 if (isArray(playlists) === false) return [] 147 if (isArray(playlists) === false) return []
147 148
148 return playlists 149 return playlists
@@ -161,7 +162,7 @@ function streamingPlaylistsModelToFormattedJSON (video: VideoModel, playlists: V
161 }) 162 })
162} 163}
163 164
164function videoFilesModelToFormattedJSON (video: VideoModel, videoFiles: VideoFileModel[]): VideoFile[] { 165function videoFilesModelToFormattedJSON (video: MVideo, videoFiles: MVideoFileRedundanciesOpt[]): VideoFile[] {
165 const { baseUrlHttp, baseUrlWs } = video.getBaseUrls() 166 const { baseUrlHttp, baseUrlWs } = video.getBaseUrls()
166 167
167 return videoFiles 168 return videoFiles
@@ -189,7 +190,7 @@ function videoFilesModelToFormattedJSON (video: VideoModel, videoFiles: VideoFil
189 }) 190 })
190} 191}
191 192
192function videoModelToActivityPubObject (video: VideoModel): VideoTorrentObject { 193function videoModelToActivityPubObject (video: MVideoAP): VideoTorrentObject {
193 const { baseUrlHttp, baseUrlWs } = video.getBaseUrls() 194 const { baseUrlHttp, baseUrlWs } = video.getBaseUrls()
194 if (!video.Tags) video.Tags = [] 195 if (!video.Tags) video.Tags = []
195 196
diff --git a/server/models/video/video-import.ts b/server/models/video/video-import.ts
index 480a671c8..f596eea9d 100644
--- a/server/models/video/video-import.ts
+++ b/server/models/video/video-import.ts
@@ -20,6 +20,8 @@ import { isVideoImportStateValid, isVideoImportTargetUrlValid } from '../../help
20import { VideoImport, VideoImportState } from '../../../shared' 20import { VideoImport, VideoImportState } from '../../../shared'
21import { isVideoMagnetUriValid } from '../../helpers/custom-validators/videos' 21import { isVideoMagnetUriValid } from '../../helpers/custom-validators/videos'
22import { UserModel } from '../account/user' 22import { UserModel } from '../account/user'
23import * as Bluebird from 'bluebird'
24import { MVideoImportDefault } from '@server/typings/models/video/video-import'
23 25
24@DefaultScope(() => ({ 26@DefaultScope(() => ({
25 include: [ 27 include: [
@@ -28,7 +30,11 @@ import { UserModel } from '../account/user'
28 required: true 30 required: true
29 }, 31 },
30 { 32 {
31 model: VideoModel.scope([ VideoModelScopeNames.WITH_ACCOUNT_DETAILS, VideoModelScopeNames.WITH_TAGS]), 33 model: VideoModel.scope([
34 VideoModelScopeNames.WITH_ACCOUNT_DETAILS,
35 VideoModelScopeNames.WITH_TAGS,
36 VideoModelScopeNames.WITH_THUMBNAILS
37 ]),
32 required: false 38 required: false
33 } 39 }
34 ] 40 ]
@@ -114,7 +120,7 @@ export class VideoImportModel extends Model<VideoImportModel> {
114 return undefined 120 return undefined
115 } 121 }
116 122
117 static loadAndPopulateVideo (id: number) { 123 static loadAndPopulateVideo (id: number): Bluebird<MVideoImportDefault> {
118 return VideoImportModel.findByPk(id) 124 return VideoImportModel.findByPk(id)
119 } 125 }
120 126
@@ -135,7 +141,7 @@ export class VideoImportModel extends Model<VideoImportModel> {
135 } 141 }
136 } 142 }
137 143
138 return VideoImportModel.findAndCountAll(query) 144 return VideoImportModel.findAndCountAll<MVideoImportDefault>(query)
139 .then(({ rows, count }) => { 145 .then(({ rows, count }) => {
140 return { 146 return {
141 data: rows, 147 data: rows,
diff --git a/server/models/video/video-playlist-element.ts b/server/models/video/video-playlist-element.ts
index dd7653533..901113161 100644
--- a/server/models/video/video-playlist-element.ts
+++ b/server/models/video/video-playlist-element.ts
@@ -25,6 +25,9 @@ import { UserModel } from '../account/user'
25import { VideoPlaylistElement, VideoPlaylistElementType } from '../../../shared/models/videos/playlist/video-playlist-element.model' 25import { VideoPlaylistElement, VideoPlaylistElementType } from '../../../shared/models/videos/playlist/video-playlist-element.model'
26import { AccountModel } from '../account/account' 26import { AccountModel } from '../account/account'
27import { VideoPrivacy } from '../../../shared/models/videos' 27import { VideoPrivacy } from '../../../shared/models/videos'
28import * as Bluebird from 'bluebird'
29import { MVideoPlaylistAP, MVideoPlaylistElement, MVideoPlaylistVideoThumbnail } from '@server/typings/models/video/video-playlist-element'
30import { MUserAccountId } from '@server/typings/models'
28 31
29@Table({ 32@Table({
30 tableName: 'videoPlaylistElement', 33 tableName: 'videoPlaylistElement',
@@ -116,7 +119,7 @@ export class VideoPlaylistElementModel extends Model<VideoPlaylistElementModel>
116 count: number, 119 count: number,
117 videoPlaylistId: number, 120 videoPlaylistId: number,
118 serverAccount: AccountModel, 121 serverAccount: AccountModel,
119 user?: UserModel 122 user?: MUserAccountId
120 }) { 123 }) {
121 const accountIds = [ options.serverAccount.id ] 124 const accountIds = [ options.serverAccount.id ]
122 const videoScope: (ScopeOptions | string)[] = [ 125 const videoScope: (ScopeOptions | string)[] = [
@@ -162,7 +165,7 @@ export class VideoPlaylistElementModel extends Model<VideoPlaylistElementModel>
162 ]).then(([ total, data ]) => ({ total, data })) 165 ]).then(([ total, data ]) => ({ total, data }))
163 } 166 }
164 167
165 static loadByPlaylistAndVideo (videoPlaylistId: number, videoId: number) { 168 static loadByPlaylistAndVideo (videoPlaylistId: number, videoId: number): Bluebird<MVideoPlaylistElement> {
166 const query = { 169 const query = {
167 where: { 170 where: {
168 videoPlaylistId, 171 videoPlaylistId,
@@ -173,11 +176,11 @@ export class VideoPlaylistElementModel extends Model<VideoPlaylistElementModel>
173 return VideoPlaylistElementModel.findOne(query) 176 return VideoPlaylistElementModel.findOne(query)
174 } 177 }
175 178
176 static loadById (playlistElementId: number) { 179 static loadById (playlistElementId: number): Bluebird<MVideoPlaylistElement> {
177 return VideoPlaylistElementModel.findByPk(playlistElementId) 180 return VideoPlaylistElementModel.findByPk(playlistElementId)
178 } 181 }
179 182
180 static loadByPlaylistAndVideoForAP (playlistId: number | string, videoId: number | string) { 183 static loadByPlaylistAndVideoForAP (playlistId: number | string, videoId: number | string): Bluebird<MVideoPlaylistAP> {
181 const playlistWhere = validator.isUUID('' + playlistId) ? { uuid: playlistId } : { id: playlistId } 184 const playlistWhere = validator.isUUID('' + playlistId) ? { uuid: playlistId } : { id: playlistId }
182 const videoWhere = validator.isUUID('' + videoId) ? { uuid: videoId } : { id: videoId } 185 const videoWhere = validator.isUUID('' + videoId) ? { uuid: videoId } : { id: videoId }
183 186
@@ -218,7 +221,7 @@ export class VideoPlaylistElementModel extends Model<VideoPlaylistElementModel>
218 }) 221 })
219 } 222 }
220 223
221 static loadFirstElementWithVideoThumbnail (videoPlaylistId: number) { 224 static loadFirstElementWithVideoThumbnail (videoPlaylistId: number): Bluebird<MVideoPlaylistVideoThumbnail> {
222 const query = { 225 const query = {
223 order: getSort('position'), 226 order: getSort('position'),
224 where: { 227 where: {
diff --git a/server/models/video/video-playlist.ts b/server/models/video/video-playlist.ts
index c8e97c491..9f1d03ac5 100644
--- a/server/models/video/video-playlist.ts
+++ b/server/models/video/video-playlist.ts
@@ -43,6 +43,14 @@ import { VideoPlaylistType } from '../../../shared/models/videos/playlist/video-
43import { ThumbnailModel } from './thumbnail' 43import { ThumbnailModel } from './thumbnail'
44import { ActivityIconObject } from '../../../shared/models/activitypub/objects' 44import { ActivityIconObject } from '../../../shared/models/activitypub/objects'
45import { FindOptions, literal, Op, ScopeOptions, Transaction, WhereOptions } from 'sequelize' 45import { FindOptions, literal, Op, ScopeOptions, Transaction, WhereOptions } from 'sequelize'
46import * as Bluebird from 'bluebird'
47import {
48 MVideoPlaylistAccountThumbnail,
49 MVideoPlaylistFull,
50 MVideoPlaylistFullSummary,
51 MVideoPlaylistIdWithElements
52} from '../../typings/models/video/video-playlist'
53import { MThumbnail } from '../../typings/models/video/thumbnail'
46 54
47enum ScopeNames { 55enum ScopeNames {
48 AVAILABLE_FOR_LIST = 'AVAILABLE_FOR_LIST', 56 AVAILABLE_FOR_LIST = 'AVAILABLE_FOR_LIST',
@@ -332,7 +340,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
332 }) 340 })
333 } 341 }
334 342
335 static listPlaylistIdsOf (accountId: number, videoIds: number[]) { 343 static listPlaylistIdsOf (accountId: number, videoIds: number[]): Bluebird<MVideoPlaylistIdWithElements[]> {
336 const query = { 344 const query = {
337 attributes: [ 'id' ], 345 attributes: [ 'id' ],
338 where: { 346 where: {
@@ -368,7 +376,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
368 .then(e => !!e) 376 .then(e => !!e)
369 } 377 }
370 378
371 static loadWithAccountAndChannelSummary (id: number | string, transaction: Transaction) { 379 static loadWithAccountAndChannelSummary (id: number | string, transaction: Transaction): Bluebird<MVideoPlaylistFullSummary> {
372 const where = buildWhereIdOrUUID(id) 380 const where = buildWhereIdOrUUID(id)
373 381
374 const query = { 382 const query = {
@@ -381,7 +389,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
381 .findOne(query) 389 .findOne(query)
382 } 390 }
383 391
384 static loadWithAccountAndChannel (id: number | string, transaction: Transaction) { 392 static loadWithAccountAndChannel (id: number | string, transaction: Transaction): Bluebird<MVideoPlaylistFull> {
385 const where = buildWhereIdOrUUID(id) 393 const where = buildWhereIdOrUUID(id)
386 394
387 const query = { 395 const query = {
@@ -394,7 +402,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
394 .findOne(query) 402 .findOne(query)
395 } 403 }
396 404
397 static loadByUrlAndPopulateAccount (url: string) { 405 static loadByUrlAndPopulateAccount (url: string): Bluebird<MVideoPlaylistAccountThumbnail> {
398 const query = { 406 const query = {
399 where: { 407 where: {
400 url 408 url
@@ -423,7 +431,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> {
423 return VideoPlaylistModel.update({ privacy: VideoPlaylistPrivacy.PRIVATE, videoChannelId: null }, query) 431 return VideoPlaylistModel.update({ privacy: VideoPlaylistPrivacy.PRIVATE, videoChannelId: null }, query)
424 } 432 }
425 433
426 async setAndSaveThumbnail (thumbnail: ThumbnailModel, t: Transaction) { 434 async setAndSaveThumbnail (thumbnail: MThumbnail, t: Transaction) {
427 thumbnail.videoPlaylistId = this.id 435 thumbnail.videoPlaylistId = this.id
428 436
429 this.Thumbnail = await thumbnail.save({ transaction: t }) 437 this.Thumbnail = await thumbnail.save({ transaction: t })
diff --git a/server/models/video/video-share.ts b/server/models/video/video-share.ts
index d8ed64557..9019b401a 100644
--- a/server/models/video/video-share.ts
+++ b/server/models/video/video-share.ts
@@ -8,6 +8,8 @@ import { buildLocalActorIdsIn, throwIfNotValid } from '../utils'
8import { VideoModel } from './video' 8import { VideoModel } from './video'
9import { VideoChannelModel } from './video-channel' 9import { VideoChannelModel } from './video-channel'
10import { Op, Transaction } from 'sequelize' 10import { Op, Transaction } from 'sequelize'
11import { MVideoShareActor, MVideoShareFull } from '../../typings/models/video'
12import { MActorDefault } from '../../typings/models'
11 13
12enum ScopeNames { 14enum ScopeNames {
13 FULL = 'FULL', 15 FULL = 'FULL',
@@ -88,7 +90,7 @@ export class VideoShareModel extends Model<VideoShareModel> {
88 }) 90 })
89 Video: VideoModel 91 Video: VideoModel
90 92
91 static load (actorId: number, videoId: number, t?: Transaction) { 93 static load (actorId: number, videoId: number, t?: Transaction): Bluebird<MVideoShareActor> {
92 return VideoShareModel.scope(ScopeNames.WITH_ACTOR).findOne({ 94 return VideoShareModel.scope(ScopeNames.WITH_ACTOR).findOne({
93 where: { 95 where: {
94 actorId, 96 actorId,
@@ -98,7 +100,7 @@ export class VideoShareModel extends Model<VideoShareModel> {
98 }) 100 })
99 } 101 }
100 102
101 static loadByUrl (url: string, t: Transaction) { 103 static loadByUrl (url: string, t: Transaction): Bluebird<MVideoShareFull> {
102 return VideoShareModel.scope(ScopeNames.FULL).findOne({ 104 return VideoShareModel.scope(ScopeNames.FULL).findOne({
103 where: { 105 where: {
104 url 106 url
@@ -107,7 +109,7 @@ export class VideoShareModel extends Model<VideoShareModel> {
107 }) 109 })
108 } 110 }
109 111
110 static loadActorsByShare (videoId: number, t: Transaction) { 112 static loadActorsByShare (videoId: number, t: Transaction): Bluebird<MActorDefault[]> {
111 const query = { 113 const query = {
112 where: { 114 where: {
113 videoId 115 videoId
@@ -122,10 +124,10 @@ export class VideoShareModel extends Model<VideoShareModel> {
122 } 124 }
123 125
124 return VideoShareModel.scope(ScopeNames.FULL).findAll(query) 126 return VideoShareModel.scope(ScopeNames.FULL).findAll(query)
125 .then(res => res.map(r => r.Actor)) 127 .then((res: MVideoShareFull[]) => res.map(r => r.Actor))
126 } 128 }
127 129
128 static loadActorsWhoSharedVideosOf (actorOwnerId: number, t: Transaction): Bluebird<ActorModel[]> { 130 static loadActorsWhoSharedVideosOf (actorOwnerId: number, t: Transaction): Bluebird<MActorDefault[]> {
129 const query = { 131 const query = {
130 attributes: [], 132 attributes: [],
131 include: [ 133 include: [
@@ -163,7 +165,7 @@ export class VideoShareModel extends Model<VideoShareModel> {
163 .then(res => res.map(r => r.Actor)) 165 .then(res => res.map(r => r.Actor))
164 } 166 }
165 167
166 static loadActorsByVideoChannel (videoChannelId: number, t: Transaction): Bluebird<ActorModel[]> { 168 static loadActorsByVideoChannel (videoChannelId: number, t: Transaction): Bluebird<MActorDefault[]> {
167 const query = { 169 const query = {
168 attributes: [], 170 attributes: [],
169 include: [ 171 include: [
diff --git a/server/models/video/video-streaming-playlist.ts b/server/models/video/video-streaming-playlist.ts
index 31dc82c54..0ea90d28c 100644
--- a/server/models/video/video-streaming-playlist.ts
+++ b/server/models/video/video-streaming-playlist.ts
@@ -1,16 +1,16 @@
1import { AllowNull, BelongsTo, Column, CreatedAt, ForeignKey, HasMany, Is, Model, Table, UpdatedAt, DataType } from 'sequelize-typescript' 1import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, HasMany, Is, Model, Table, UpdatedAt } from 'sequelize-typescript'
2import { isVideoFileInfoHashValid } from '../../helpers/custom-validators/videos' 2import { isVideoFileInfoHashValid } from '../../helpers/custom-validators/videos'
3import { throwIfNotValid } from '../utils' 3import { throwIfNotValid } from '../utils'
4import { VideoModel } from './video' 4import { VideoModel } from './video'
5import { VideoRedundancyModel } from '../redundancy/video-redundancy' 5import { VideoRedundancyModel } from '../redundancy/video-redundancy'
6import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type' 6import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type'
7import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' 7import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
8import { CONSTRAINTS_FIELDS, STATIC_PATHS, P2P_MEDIA_LOADER_PEER_VERSION } from '../../initializers/constants' 8import { CONSTRAINTS_FIELDS, P2P_MEDIA_LOADER_PEER_VERSION, STATIC_PATHS } from '../../initializers/constants'
9import { VideoFileModel } from './video-file'
10import { join } from 'path' 9import { join } from 'path'
11import { sha1 } from '../../helpers/core-utils' 10import { sha1 } from '../../helpers/core-utils'
12import { isArrayOf } from '../../helpers/custom-validators/misc' 11import { isArrayOf } from '../../helpers/custom-validators/misc'
13import { QueryTypes, Op } from 'sequelize' 12import { Op, QueryTypes } from 'sequelize'
13import { MStreamingPlaylist, MVideoFile } from '@server/typings/models'
14 14
15@Table({ 15@Table({
16 tableName: 'videoStreamingPlaylist', 16 tableName: 'videoStreamingPlaylist',
@@ -91,7 +91,7 @@ export class VideoStreamingPlaylistModel extends Model<VideoStreamingPlaylistMod
91 .then(results => results.length === 1) 91 .then(results => results.length === 1)
92 } 92 }
93 93
94 static buildP2PMediaLoaderInfoHashes (playlistUrl: string, videoFiles: VideoFileModel[]) { 94 static buildP2PMediaLoaderInfoHashes (playlistUrl: string, videoFiles: MVideoFile[]) {
95 const hashes: string[] = [] 95 const hashes: string[] = []
96 96
97 // https://github.com/Novage/p2p-media-loader/blob/master/p2p-media-loader-core/lib/p2p-media-manager.ts#L115 97 // https://github.com/Novage/p2p-media-loader/blob/master/p2p-media-loader-core/lib/p2p-media-manager.ts#L115
@@ -165,7 +165,7 @@ export class VideoStreamingPlaylistModel extends Model<VideoStreamingPlaylistMod
165 return baseUrlHttp + STATIC_PATHS.REDUNDANCY + this.getStringType() + '/' + this.Video.uuid 165 return baseUrlHttp + STATIC_PATHS.REDUNDANCY + this.getStringType() + '/' + this.Video.uuid
166 } 166 }
167 167
168 hasSameUniqueKeysThan (other: VideoStreamingPlaylistModel) { 168 hasSameUniqueKeysThan (other: MStreamingPlaylist) {
169 return this.type === other.type && 169 return this.type === other.type &&
170 this.videoId === other.videoId 170 this.videoId === other.videoId
171 } 171 }
diff --git a/server/models/video/video.ts b/server/models/video/video.ts
index b59df397d..7b1f0bc31 100644
--- a/server/models/video/video.ts
+++ b/server/models/video/video.ts
@@ -36,7 +36,7 @@ import {
36 Table, 36 Table,
37 UpdatedAt 37 UpdatedAt
38} from 'sequelize-typescript' 38} from 'sequelize-typescript'
39import { UserRight, VideoPrivacy, VideoResolution, VideoState } from '../../../shared' 39import { UserRight, VideoPrivacy, VideoState } from '../../../shared'
40import { VideoTorrentObject } from '../../../shared/models/activitypub/objects' 40import { VideoTorrentObject } from '../../../shared/models/activitypub/objects'
41import { Video, VideoDetails, VideoFile } from '../../../shared/models/videos' 41import { Video, VideoDetails, VideoFile } from '../../../shared/models/videos'
42import { VideoFilter } from '../../../shared/models/videos/video-query.type' 42import { VideoFilter } from '../../../shared/models/videos/video-query.type'
@@ -111,7 +111,6 @@ import {
111 videoModelToFormattedJSON 111 videoModelToFormattedJSON
112} from './video-format-utils' 112} from './video-format-utils'
113import { UserVideoHistoryModel } from '../account/user-video-history' 113import { UserVideoHistoryModel } from '../account/user-video-history'
114import { UserModel } from '../account/user'
115import { VideoImportModel } from './video-import' 114import { VideoImportModel } from './video-import'
116import { VideoStreamingPlaylistModel } from './video-streaming-playlist' 115import { VideoStreamingPlaylistModel } from './video-streaming-playlist'
117import { VideoPlaylistElementModel } from './video-playlist-element' 116import { VideoPlaylistElementModel } from './video-playlist-element'
@@ -120,6 +119,24 @@ import { ThumbnailModel } from './thumbnail'
120import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type' 119import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type'
121import { createTorrentPromise } from '../../helpers/webtorrent' 120import { createTorrentPromise } from '../../helpers/webtorrent'
122import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type' 121import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type'
122import {
123 MChannel,
124 MChannelActorAccountDefault,
125 MChannelId,
126 MUserAccountId,
127 MUserId,
128 MVideoAccountAllFiles,
129 MVideoAccountLight,
130 MVideoDetails,
131 MVideoFullLight,
132 MVideoIdThumbnail,
133 MVideoThumbnail,
134 MVideoWithAllFiles,
135 MVideoWithBlacklistThumbnailScheduled,
136 MVideoWithRights
137} from '../../typings/models'
138import { MVideoFile, MVideoFileRedundanciesOpt } from '../../typings/models/video/video-file'
139import { MThumbnail } from '../../typings/models/video/thumbnail'
123 140
124// FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation 141// FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation
125const indexes: (ModelIndexesOptions & { where?: WhereOptions })[] = [ 142const indexes: (ModelIndexesOptions & { where?: WhereOptions })[] = [
@@ -232,8 +249,8 @@ export type AvailableForListIDsOptions = {
232 videoPlaylistId?: number 249 videoPlaylistId?: number
233 250
234 trendingDays?: number 251 trendingDays?: number
235 user?: UserModel, 252 user?: MUserAccountId
236 historyOfUser?: UserModel 253 historyOfUser?: MUserId
237 254
238 baseWhere?: WhereOptions[] 255 baseWhere?: WhereOptions[]
239} 256}
@@ -634,7 +651,7 @@ export type AvailableForListIDsOptions = {
634 [ ScopeNames.WITH_BLACKLISTED ]: { 651 [ ScopeNames.WITH_BLACKLISTED ]: {
635 include: [ 652 include: [
636 { 653 {
637 attributes: [ 'id', 'reason' ], 654 attributes: [ 'id', 'reason', 'unfederated' ],
638 model: VideoBlacklistModel, 655 model: VideoBlacklistModel,
639 required: false 656 required: false
640 } 657 }
@@ -989,18 +1006,16 @@ export class VideoModel extends Model<VideoModel> {
989 VideoCaptions: VideoCaptionModel[] 1006 VideoCaptions: VideoCaptionModel[]
990 1007
991 @BeforeDestroy 1008 @BeforeDestroy
992 static async sendDelete (instance: VideoModel, options) { 1009 static async sendDelete (instance: MVideoAccountLight, options) {
993 if (instance.isOwned()) { 1010 if (instance.isOwned()) {
994 if (!instance.VideoChannel) { 1011 if (!instance.VideoChannel) {
995 instance.VideoChannel = await instance.$get('VideoChannel', { 1012 instance.VideoChannel = await instance.$get('VideoChannel', {
996 include: [ 1013 include: [
997 { 1014 ActorModel,
998 model: AccountModel, 1015 AccountModel
999 include: [ ActorModel ]
1000 }
1001 ], 1016 ],
1002 transaction: options.transaction 1017 transaction: options.transaction
1003 }) as VideoChannelModel 1018 }) as MChannelActorAccountDefault
1004 } 1019 }
1005 1020
1006 return sendDeleteVideo(instance, options.transaction) 1021 return sendDeleteVideo(instance, options.transaction)
@@ -1039,7 +1054,7 @@ export class VideoModel extends Model<VideoModel> {
1039 return undefined 1054 return undefined
1040 } 1055 }
1041 1056
1042 static listLocal () { 1057 static listLocal (): Bluebird<MVideoWithAllFiles[]> {
1043 const query = { 1058 const query = {
1044 where: { 1059 where: {
1045 remote: false 1060 remote: false
@@ -1159,7 +1174,7 @@ export class VideoModel extends Model<VideoModel> {
1159 }) 1174 })
1160 } 1175 }
1161 1176
1162 static listUserVideosForApi (accountId: number, start: number, count: number, sort: string, withFiles = false) { 1177 static listUserVideosForApi (accountId: number, start: number, count: number, sort: string) {
1163 function buildBaseQuery (): FindOptions { 1178 function buildBaseQuery (): FindOptions {
1164 return { 1179 return {
1165 offset: start, 1180 offset: start,
@@ -1192,19 +1207,12 @@ export class VideoModel extends Model<VideoModel> {
1192 ScopeNames.WITH_THUMBNAILS 1207 ScopeNames.WITH_THUMBNAILS
1193 ] 1208 ]
1194 1209
1195 if (withFiles === true) {
1196 findQuery.include.push({
1197 model: VideoFileModel.unscoped(),
1198 required: true
1199 })
1200 }
1201
1202 return Promise.all([ 1210 return Promise.all([
1203 VideoModel.count(countQuery), 1211 VideoModel.count(countQuery),
1204 VideoModel.scope(findScopes).findAll(findQuery) 1212 VideoModel.scope(findScopes).findAll(findQuery)
1205 ]).then(([ count, rows ]) => { 1213 ]).then(([ count, rows ]) => {
1206 return { 1214 return {
1207 data: rows, 1215 data: rows as MVideoWithBlacklistThumbnailScheduled[],
1208 total: count 1216 total: count
1209 } 1217 }
1210 }) 1218 })
@@ -1228,8 +1236,8 @@ export class VideoModel extends Model<VideoModel> {
1228 followerActorId?: number 1236 followerActorId?: number
1229 videoPlaylistId?: number, 1237 videoPlaylistId?: number,
1230 trendingDays?: number, 1238 trendingDays?: number,
1231 user?: UserModel, 1239 user?: MUserAccountId,
1232 historyOfUser?: UserModel 1240 historyOfUser?: MUserId
1233 }, countVideos = true) { 1241 }, countVideos = true) {
1234 if (options.filter && options.filter === 'all-local' && !options.user.hasRight(UserRight.SEE_ALL_VIDEOS)) { 1242 if (options.filter && options.filter === 'all-local' && !options.user.hasRight(UserRight.SEE_ALL_VIDEOS)) {
1235 throw new Error('Try to filter all-local but no user has not the see all videos right') 1243 throw new Error('Try to filter all-local but no user has not the see all videos right')
@@ -1294,7 +1302,7 @@ export class VideoModel extends Model<VideoModel> {
1294 tagsAllOf?: string[] 1302 tagsAllOf?: string[]
1295 durationMin?: number // seconds 1303 durationMin?: number // seconds
1296 durationMax?: number // seconds 1304 durationMax?: number // seconds
1297 user?: UserModel, 1305 user?: MUserAccountId,
1298 filter?: VideoFilter 1306 filter?: VideoFilter
1299 }) { 1307 }) {
1300 const whereAnd = [] 1308 const whereAnd = []
@@ -1387,7 +1395,7 @@ export class VideoModel extends Model<VideoModel> {
1387 return VideoModel.getAvailableForApi(query, queryOptions) 1395 return VideoModel.getAvailableForApi(query, queryOptions)
1388 } 1396 }
1389 1397
1390 static load (id: number | string, t?: Transaction) { 1398 static load (id: number | string, t?: Transaction): Bluebird<MVideoThumbnail> {
1391 const where = buildWhereIdOrUUID(id) 1399 const where = buildWhereIdOrUUID(id)
1392 const options = { 1400 const options = {
1393 where, 1401 where,
@@ -1397,7 +1405,7 @@ export class VideoModel extends Model<VideoModel> {
1397 return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(options) 1405 return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(options)
1398 } 1406 }
1399 1407
1400 static loadWithRights (id: number | string, t?: Transaction) { 1408 static loadWithRights (id: number | string, t?: Transaction): Bluebird<MVideoWithRights> {
1401 const where = buildWhereIdOrUUID(id) 1409 const where = buildWhereIdOrUUID(id)
1402 const options = { 1410 const options = {
1403 where, 1411 where,
@@ -1411,7 +1419,7 @@ export class VideoModel extends Model<VideoModel> {
1411 ]).findOne(options) 1419 ]).findOne(options)
1412 } 1420 }
1413 1421
1414 static loadOnlyId (id: number | string, t?: Transaction) { 1422 static loadOnlyId (id: number | string, t?: Transaction): Bluebird<MVideoIdThumbnail> {
1415 const where = buildWhereIdOrUUID(id) 1423 const where = buildWhereIdOrUUID(id)
1416 1424
1417 const options = { 1425 const options = {
@@ -1423,7 +1431,7 @@ export class VideoModel extends Model<VideoModel> {
1423 return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(options) 1431 return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(options)
1424 } 1432 }
1425 1433
1426 static loadWithFiles (id: number | string, t?: Transaction, logging?: boolean) { 1434 static loadWithFiles (id: number | string, t?: Transaction, logging?: boolean): Bluebird<MVideoWithAllFiles> {
1427 const where = buildWhereIdOrUUID(id) 1435 const where = buildWhereIdOrUUID(id)
1428 1436
1429 const query = { 1437 const query = {
@@ -1439,7 +1447,7 @@ export class VideoModel extends Model<VideoModel> {
1439 ]).findOne(query) 1447 ]).findOne(query)
1440 } 1448 }
1441 1449
1442 static loadByUUID (uuid: string) { 1450 static loadByUUID (uuid: string): Bluebird<MVideoThumbnail> {
1443 const options = { 1451 const options = {
1444 where: { 1452 where: {
1445 uuid 1453 uuid
@@ -1449,7 +1457,7 @@ export class VideoModel extends Model<VideoModel> {
1449 return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(options) 1457 return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(options)
1450 } 1458 }
1451 1459
1452 static loadByUrl (url: string, transaction?: Transaction) { 1460 static loadByUrl (url: string, transaction?: Transaction): Bluebird<MVideoThumbnail> {
1453 const query: FindOptions = { 1461 const query: FindOptions = {
1454 where: { 1462 where: {
1455 url 1463 url
@@ -1460,7 +1468,7 @@ export class VideoModel extends Model<VideoModel> {
1460 return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(query) 1468 return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(query)
1461 } 1469 }
1462 1470
1463 static loadByUrlAndPopulateAccount (url: string, transaction?: Transaction) { 1471 static loadByUrlAndPopulateAccount (url: string, transaction?: Transaction): Bluebird<MVideoAccountAllFiles> {
1464 const query: FindOptions = { 1472 const query: FindOptions = {
1465 where: { 1473 where: {
1466 url 1474 url
@@ -1472,11 +1480,12 @@ export class VideoModel extends Model<VideoModel> {
1472 ScopeNames.WITH_ACCOUNT_DETAILS, 1480 ScopeNames.WITH_ACCOUNT_DETAILS,
1473 ScopeNames.WITH_FILES, 1481 ScopeNames.WITH_FILES,
1474 ScopeNames.WITH_STREAMING_PLAYLISTS, 1482 ScopeNames.WITH_STREAMING_PLAYLISTS,
1475 ScopeNames.WITH_THUMBNAILS 1483 ScopeNames.WITH_THUMBNAILS,
1484 ScopeNames.WITH_BLACKLISTED
1476 ]).findOne(query) 1485 ]).findOne(query)
1477 } 1486 }
1478 1487
1479 static loadAndPopulateAccountAndServerAndTags (id: number | string, t?: Transaction, userId?: number) { 1488 static loadAndPopulateAccountAndServerAndTags (id: number | string, t?: Transaction, userId?: number): Bluebird<MVideoFullLight> {
1480 const where = buildWhereIdOrUUID(id) 1489 const where = buildWhereIdOrUUID(id)
1481 1490
1482 const options = { 1491 const options = {
@@ -1508,7 +1517,7 @@ export class VideoModel extends Model<VideoModel> {
1508 id: number | string, 1517 id: number | string,
1509 t?: Transaction, 1518 t?: Transaction,
1510 userId?: number 1519 userId?: number
1511 }) { 1520 }): Bluebird<MVideoDetails> {
1512 const { id, t, userId } = parameters 1521 const { id, t, userId } = parameters
1513 const where = buildWhereIdOrUUID(id) 1522 const where = buildWhereIdOrUUID(id)
1514 1523
@@ -1586,7 +1595,7 @@ export class VideoModel extends Model<VideoModel> {
1586 .then(results => results.length === 1) 1595 .then(results => results.length === 1)
1587 } 1596 }
1588 1597
1589 static bulkUpdateSupportField (videoChannel: VideoChannelModel, t: Transaction) { 1598 static bulkUpdateSupportField (videoChannel: MChannel, t: Transaction) {
1590 const options = { 1599 const options = {
1591 where: { 1600 where: {
1592 channelId: videoChannel.id 1601 channelId: videoChannel.id
@@ -1597,7 +1606,7 @@ export class VideoModel extends Model<VideoModel> {
1597 return VideoModel.update({ support: videoChannel.support }, options) 1606 return VideoModel.update({ support: videoChannel.support }, options)
1598 } 1607 }
1599 1608
1600 static getAllIdsFromChannel (videoChannel: VideoChannelModel) { 1609 static getAllIdsFromChannel (videoChannel: MChannelId): Bluebird<number[]> {
1601 const query = { 1610 const query = {
1602 attributes: [ 'id' ], 1611 attributes: [ 'id' ],
1603 where: { 1612 where: {
@@ -1769,7 +1778,7 @@ export class VideoModel extends Model<VideoModel> {
1769 return this.VideoFiles.find(f => f.resolution === resolution) 1778 return this.VideoFiles.find(f => f.resolution === resolution)
1770 } 1779 }
1771 1780
1772 async addAndSaveThumbnail (thumbnail: ThumbnailModel, transaction: Transaction) { 1781 async addAndSaveThumbnail (thumbnail: MThumbnail, transaction: Transaction) {
1773 thumbnail.videoId = this.id 1782 thumbnail.videoId = this.id
1774 1783
1775 const savedThumbnail = await thumbnail.save({ transaction }) 1784 const savedThumbnail = await thumbnail.save({ transaction })
@@ -1782,7 +1791,7 @@ export class VideoModel extends Model<VideoModel> {
1782 this.Thumbnails.push(savedThumbnail) 1791 this.Thumbnails.push(savedThumbnail)
1783 } 1792 }
1784 1793
1785 getVideoFilename (videoFile: VideoFileModel) { 1794 getVideoFilename (videoFile: MVideoFile) {
1786 return this.uuid + '-' + videoFile.resolution + videoFile.extname 1795 return this.uuid + '-' + videoFile.resolution + videoFile.extname
1787 } 1796 }
1788 1797
@@ -1806,7 +1815,7 @@ export class VideoModel extends Model<VideoModel> {
1806 return this.Thumbnails.find(t => t.type === ThumbnailType.PREVIEW) 1815 return this.Thumbnails.find(t => t.type === ThumbnailType.PREVIEW)
1807 } 1816 }
1808 1817
1809 getTorrentFileName (videoFile: VideoFileModel) { 1818 getTorrentFileName (videoFile: MVideoFile) {
1810 const extension = '.torrent' 1819 const extension = '.torrent'
1811 return this.uuid + '-' + videoFile.resolution + extension 1820 return this.uuid + '-' + videoFile.resolution + extension
1812 } 1821 }
@@ -1815,15 +1824,15 @@ export class VideoModel extends Model<VideoModel> {
1815 return this.remote === false 1824 return this.remote === false
1816 } 1825 }
1817 1826
1818 getTorrentFilePath (videoFile: VideoFileModel) { 1827 getTorrentFilePath (videoFile: MVideoFile) {
1819 return join(CONFIG.STORAGE.TORRENTS_DIR, this.getTorrentFileName(videoFile)) 1828 return join(CONFIG.STORAGE.TORRENTS_DIR, this.getTorrentFileName(videoFile))
1820 } 1829 }
1821 1830
1822 getVideoFilePath (videoFile: VideoFileModel) { 1831 getVideoFilePath (videoFile: MVideoFile) {
1823 return join(CONFIG.STORAGE.VIDEOS_DIR, this.getVideoFilename(videoFile)) 1832 return join(CONFIG.STORAGE.VIDEOS_DIR, this.getVideoFilename(videoFile))
1824 } 1833 }
1825 1834
1826 async createTorrentAndSetInfoHash (videoFile: VideoFileModel) { 1835 async createTorrentAndSetInfoHash (videoFile: MVideoFile) {
1827 const options = { 1836 const options = {
1828 // Keep the extname, it's used by the client to stream the file inside a web browser 1837 // Keep the extname, it's used by the client to stream the file inside a web browser
1829 name: `${this.name} ${videoFile.resolution}p${videoFile.extname}`, 1838 name: `${this.name} ${videoFile.resolution}p${videoFile.extname}`,
@@ -1908,7 +1917,7 @@ export class VideoModel extends Model<VideoModel> {
1908 return this.VideoStreamingPlaylists.find(p => p.type === VideoStreamingPlaylistType.HLS) 1917 return this.VideoStreamingPlaylists.find(p => p.type === VideoStreamingPlaylistType.HLS)
1909 } 1918 }
1910 1919
1911 removeFile (videoFile: VideoFileModel, isRedundancy = false) { 1920 removeFile (videoFile: MVideoFile, isRedundancy = false) {
1912 const baseDir = isRedundancy ? CONFIG.STORAGE.REDUNDANCY_DIR : CONFIG.STORAGE.VIDEOS_DIR 1921 const baseDir = isRedundancy ? CONFIG.STORAGE.REDUNDANCY_DIR : CONFIG.STORAGE.VIDEOS_DIR
1913 1922
1914 const filePath = join(baseDir, this.getVideoFilename(videoFile)) 1923 const filePath = join(baseDir, this.getVideoFilename(videoFile))
@@ -1916,7 +1925,7 @@ export class VideoModel extends Model<VideoModel> {
1916 .catch(err => logger.warn('Cannot delete file %s.', filePath, { err })) 1925 .catch(err => logger.warn('Cannot delete file %s.', filePath, { err }))
1917 } 1926 }
1918 1927
1919 removeTorrent (videoFile: VideoFileModel) { 1928 removeTorrent (videoFile: MVideoFile) {
1920 const torrentPath = join(CONFIG.STORAGE.TORRENTS_DIR, this.getTorrentFileName(videoFile)) 1929 const torrentPath = join(CONFIG.STORAGE.TORRENTS_DIR, this.getTorrentFileName(videoFile))
1921 return remove(torrentPath) 1930 return remove(torrentPath)
1922 .catch(err => logger.warn('Cannot delete torrent %s.', torrentPath, { err })) 1931 .catch(err => logger.warn('Cannot delete torrent %s.', torrentPath, { err }))
@@ -1957,7 +1966,7 @@ export class VideoModel extends Model<VideoModel> {
1957 return { baseUrlHttp, baseUrlWs } 1966 return { baseUrlHttp, baseUrlWs }
1958 } 1967 }
1959 1968
1960 generateMagnetUri (videoFile: VideoFileModel, baseUrlHttp: string, baseUrlWs: string) { 1969 generateMagnetUri (videoFile: MVideoFileRedundanciesOpt, baseUrlHttp: string, baseUrlWs: string) {
1961 const xs = this.getTorrentUrl(videoFile, baseUrlHttp) 1970 const xs = this.getTorrentUrl(videoFile, baseUrlHttp)
1962 const announce = this.getTrackerUrls(baseUrlHttp, baseUrlWs) 1971 const announce = this.getTrackerUrls(baseUrlHttp, baseUrlWs)
1963 let urlList = [ this.getVideoFileUrl(videoFile, baseUrlHttp) ] 1972 let urlList = [ this.getVideoFileUrl(videoFile, baseUrlHttp) ]
@@ -1980,27 +1989,27 @@ export class VideoModel extends Model<VideoModel> {
1980 return [ baseUrlWs + '/tracker/socket', baseUrlHttp + '/tracker/announce' ] 1989 return [ baseUrlWs + '/tracker/socket', baseUrlHttp + '/tracker/announce' ]
1981 } 1990 }
1982 1991
1983 getTorrentUrl (videoFile: VideoFileModel, baseUrlHttp: string) { 1992 getTorrentUrl (videoFile: MVideoFile, baseUrlHttp: string) {
1984 return baseUrlHttp + STATIC_PATHS.TORRENTS + this.getTorrentFileName(videoFile) 1993 return baseUrlHttp + STATIC_PATHS.TORRENTS + this.getTorrentFileName(videoFile)
1985 } 1994 }
1986 1995
1987 getTorrentDownloadUrl (videoFile: VideoFileModel, baseUrlHttp: string) { 1996 getTorrentDownloadUrl (videoFile: MVideoFile, baseUrlHttp: string) {
1988 return baseUrlHttp + STATIC_DOWNLOAD_PATHS.TORRENTS + this.getTorrentFileName(videoFile) 1997 return baseUrlHttp + STATIC_DOWNLOAD_PATHS.TORRENTS + this.getTorrentFileName(videoFile)
1989 } 1998 }
1990 1999
1991 getVideoFileUrl (videoFile: VideoFileModel, baseUrlHttp: string) { 2000 getVideoFileUrl (videoFile: MVideoFile, baseUrlHttp: string) {
1992 return baseUrlHttp + STATIC_PATHS.WEBSEED + this.getVideoFilename(videoFile) 2001 return baseUrlHttp + STATIC_PATHS.WEBSEED + this.getVideoFilename(videoFile)
1993 } 2002 }
1994 2003
1995 getVideoRedundancyUrl (videoFile: VideoFileModel, baseUrlHttp: string) { 2004 getVideoRedundancyUrl (videoFile: MVideoFile, baseUrlHttp: string) {
1996 return baseUrlHttp + STATIC_PATHS.REDUNDANCY + this.getVideoFilename(videoFile) 2005 return baseUrlHttp + STATIC_PATHS.REDUNDANCY + this.getVideoFilename(videoFile)
1997 } 2006 }
1998 2007
1999 getVideoFileDownloadUrl (videoFile: VideoFileModel, baseUrlHttp: string) { 2008 getVideoFileDownloadUrl (videoFile: MVideoFile, baseUrlHttp: string) {
2000 return baseUrlHttp + STATIC_DOWNLOAD_PATHS.VIDEOS + this.getVideoFilename(videoFile) 2009 return baseUrlHttp + STATIC_DOWNLOAD_PATHS.VIDEOS + this.getVideoFilename(videoFile)
2001 } 2010 }
2002 2011
2003 getBandwidthBits (videoFile: VideoFileModel) { 2012 getBandwidthBits (videoFile: MVideoFile) {
2004 return Math.ceil((videoFile.size * 8) / this.duration) 2013 return Math.ceil((videoFile.size * 8) / this.duration)
2005 } 2014 }
2006} 2015}