diff options
Diffstat (limited to 'server/models/video')
-rw-r--r-- | server/models/video/schedule-video-update.ts | 3 | ||||
-rw-r--r-- | server/models/video/tag.ts | 15 | ||||
-rw-r--r-- | server/models/video/video-abuse.ts | 27 | ||||
-rw-r--r-- | server/models/video/video-blacklist.ts | 10 | ||||
-rw-r--r-- | server/models/video/video-caption.ts | 16 | ||||
-rw-r--r-- | server/models/video/video-change-ownership.ts | 8 | ||||
-rw-r--r-- | server/models/video/video-channel.ts | 69 | ||||
-rw-r--r-- | server/models/video/video-comment.ts | 87 | ||||
-rw-r--r-- | server/models/video/video-file.ts | 3 | ||||
-rw-r--r-- | server/models/video/video-format-utils.ts | 17 | ||||
-rw-r--r-- | server/models/video/video-import.ts | 14 | ||||
-rw-r--r-- | server/models/video/video-playlist-element.ts | 34 | ||||
-rw-r--r-- | server/models/video/video-playlist.ts | 23 | ||||
-rw-r--r-- | server/models/video/video-share.ts | 14 | ||||
-rw-r--r-- | server/models/video/video-streaming-playlist.ts | 12 | ||||
-rw-r--r-- | server/models/video/video.ts | 149 |
16 files changed, 287 insertions, 214 deletions
diff --git a/server/models/video/schedule-video-update.ts b/server/models/video/schedule-video-update.ts index 603d55692..fc2a424aa 100644 --- a/server/models/video/schedule-video-update.ts +++ b/server/models/video/schedule-video-update.ts | |||
@@ -2,6 +2,7 @@ import { AllowNull, BelongsTo, Column, CreatedAt, Default, ForeignKey, Model, Ta | |||
2 | import { ScopeNames as VideoScopeNames, VideoModel } from './video' | 2 | import { ScopeNames as VideoScopeNames, VideoModel } from './video' |
3 | import { VideoPrivacy } from '../../../shared/models/videos' | 3 | import { VideoPrivacy } from '../../../shared/models/videos' |
4 | import { Op, Transaction } from 'sequelize' | 4 | import { Op, Transaction } from 'sequelize' |
5 | import { MScheduleVideoUpdateFormattable } from '@server/typings/models' | ||
5 | 6 | ||
6 | @Table({ | 7 | @Table({ |
7 | tableName: 'scheduleVideoUpdate', | 8 | tableName: 'scheduleVideoUpdate', |
@@ -96,7 +97,7 @@ export class ScheduleVideoUpdateModel extends Model<ScheduleVideoUpdateModel> { | |||
96 | return ScheduleVideoUpdateModel.destroy(query) | 97 | return ScheduleVideoUpdateModel.destroy(query) |
97 | } | 98 | } |
98 | 99 | ||
99 | toFormattedJSON () { | 100 | toFormattedJSON (this: MScheduleVideoUpdateFormattable) { |
100 | return { | 101 | return { |
101 | updateAt: this.updateAt, | 102 | updateAt: this.updateAt, |
102 | privacy: this.privacy || undefined | 103 | privacy: this.privacy || undefined |
diff --git a/server/models/video/tag.ts b/server/models/video/tag.ts index 0fc3cfd4c..ed8df8b48 100644 --- a/server/models/video/tag.ts +++ b/server/models/video/tag.ts | |||
@@ -1,11 +1,12 @@ | |||
1 | import * as Bluebird from 'bluebird' | 1 | import * as Bluebird from 'bluebird' |
2 | import { QueryTypes, Transaction } from 'sequelize' | 2 | import { fn, QueryTypes, Transaction, col } from 'sequelize' |
3 | import { AllowNull, BelongsToMany, Column, CreatedAt, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' | 3 | import { AllowNull, BelongsToMany, Column, CreatedAt, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' |
4 | import { isVideoTagValid } from '../../helpers/custom-validators/videos' | 4 | import { isVideoTagValid } from '../../helpers/custom-validators/videos' |
5 | import { throwIfNotValid } from '../utils' | 5 | import { throwIfNotValid } from '../utils' |
6 | import { VideoModel } from './video' | 6 | import { VideoModel } from './video' |
7 | import { VideoTagModel } from './video-tag' | 7 | import { VideoTagModel } from './video-tag' |
8 | import { VideoPrivacy, VideoState } from '../../../shared/models/videos' | 8 | import { VideoPrivacy, VideoState } from '../../../shared/models/videos' |
9 | import { MTag } from '@server/typings/models' | ||
9 | 10 | ||
10 | @Table({ | 11 | @Table({ |
11 | tableName: 'tag', | 12 | tableName: 'tag', |
@@ -14,6 +15,10 @@ import { VideoPrivacy, VideoState } from '../../../shared/models/videos' | |||
14 | { | 15 | { |
15 | fields: [ 'name' ], | 16 | fields: [ 'name' ], |
16 | unique: true | 17 | unique: true |
18 | }, | ||
19 | { | ||
20 | name: 'tag_lower_name', | ||
21 | fields: [ fn('lower', col('name')) ] as any // FIXME: typings | ||
17 | } | 22 | } |
18 | ] | 23 | ] |
19 | }) | 24 | }) |
@@ -37,10 +42,10 @@ export class TagModel extends Model<TagModel> { | |||
37 | }) | 42 | }) |
38 | Videos: VideoModel[] | 43 | Videos: VideoModel[] |
39 | 44 | ||
40 | static findOrCreateTags (tags: string[], transaction: Transaction) { | 45 | static findOrCreateTags (tags: string[], transaction: Transaction): Promise<MTag[]> { |
41 | if (tags === null) return [] | 46 | if (tags === null) return Promise.resolve([]) |
42 | 47 | ||
43 | const tasks: Bluebird<TagModel>[] = [] | 48 | const tasks: Bluebird<MTag>[] = [] |
44 | tags.forEach(tag => { | 49 | tags.forEach(tag => { |
45 | const query = { | 50 | const query = { |
46 | where: { | 51 | where: { |
@@ -52,7 +57,7 @@ export class TagModel extends Model<TagModel> { | |||
52 | transaction | 57 | transaction |
53 | } | 58 | } |
54 | 59 | ||
55 | const promise = TagModel.findOrCreate(query) | 60 | const promise = TagModel.findOrCreate<MTag>(query) |
56 | .then(([ tagInstance ]) => tagInstance) | 61 | .then(([ tagInstance ]) => tagInstance) |
57 | tasks.push(promise) | 62 | tasks.push(promise) |
58 | }) | 63 | }) |
diff --git a/server/models/video/video-abuse.ts b/server/models/video/video-abuse.ts index 1ac7919b3..3636db18d 100644 --- a/server/models/video/video-abuse.ts +++ b/server/models/video/video-abuse.ts | |||
@@ -7,10 +7,13 @@ import { | |||
7 | isVideoAbuseStateValid | 7 | isVideoAbuseStateValid |
8 | } from '../../helpers/custom-validators/video-abuses' | 8 | } from '../../helpers/custom-validators/video-abuses' |
9 | import { AccountModel } from '../account/account' | 9 | import { AccountModel } from '../account/account' |
10 | import { getSort, throwIfNotValid } from '../utils' | 10 | import { buildBlockedAccountSQL, getSort, throwIfNotValid } from '../utils' |
11 | import { VideoModel } from './video' | 11 | import { VideoModel } from './video' |
12 | import { VideoAbuseState } from '../../../shared' | 12 | import { VideoAbuseState } from '../../../shared' |
13 | import { CONSTRAINTS_FIELDS, VIDEO_ABUSE_STATES } from '../../initializers/constants' | 13 | import { CONSTRAINTS_FIELDS, VIDEO_ABUSE_STATES } from '../../initializers/constants' |
14 | import { MUserAccountId, MVideoAbuse, MVideoAbuseFormattable, MVideoAbuseVideo } from '../../typings/models' | ||
15 | import * as Bluebird from 'bluebird' | ||
16 | import { literal, Op } from 'sequelize' | ||
14 | 17 | ||
15 | @Table({ | 18 | @Table({ |
16 | tableName: 'videoAbuse', | 19 | tableName: 'videoAbuse', |
@@ -73,7 +76,7 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> { | |||
73 | }) | 76 | }) |
74 | Video: VideoModel | 77 | Video: VideoModel |
75 | 78 | ||
76 | static loadByIdAndVideoId (id: number, videoId: number) { | 79 | static loadByIdAndVideoId (id: number, videoId: number): Bluebird<MVideoAbuse> { |
77 | const query = { | 80 | const query = { |
78 | where: { | 81 | where: { |
79 | id, | 82 | id, |
@@ -83,11 +86,25 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> { | |||
83 | return VideoAbuseModel.findOne(query) | 86 | return VideoAbuseModel.findOne(query) |
84 | } | 87 | } |
85 | 88 | ||
86 | static listForApi (start: number, count: number, sort: string) { | 89 | static listForApi (parameters: { |
90 | start: number, | ||
91 | count: number, | ||
92 | sort: string, | ||
93 | serverAccountId: number | ||
94 | user?: MUserAccountId | ||
95 | }) { | ||
96 | const { start, count, sort, user, serverAccountId } = parameters | ||
97 | const userAccountId = user ? user.Account.id : undefined | ||
98 | |||
87 | const query = { | 99 | const query = { |
88 | offset: start, | 100 | offset: start, |
89 | limit: count, | 101 | limit: count, |
90 | order: getSort(sort), | 102 | order: getSort(sort), |
103 | where: { | ||
104 | reporterAccountId: { | ||
105 | [Op.notIn]: literal('(' + buildBlockedAccountSQL(serverAccountId, userAccountId) + ')') | ||
106 | } | ||
107 | }, | ||
91 | include: [ | 108 | include: [ |
92 | { | 109 | { |
93 | model: AccountModel, | 110 | model: AccountModel, |
@@ -106,7 +123,7 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> { | |||
106 | }) | 123 | }) |
107 | } | 124 | } |
108 | 125 | ||
109 | toFormattedJSON (): VideoAbuse { | 126 | toFormattedJSON (this: MVideoAbuseFormattable): VideoAbuse { |
110 | return { | 127 | return { |
111 | id: this.id, | 128 | id: this.id, |
112 | reason: this.reason, | 129 | reason: this.reason, |
@@ -125,7 +142,7 @@ export class VideoAbuseModel extends Model<VideoAbuseModel> { | |||
125 | } | 142 | } |
126 | } | 143 | } |
127 | 144 | ||
128 | toActivityPubObject (): VideoAbuseObject { | 145 | toActivityPubObject (this: MVideoAbuseVideo): VideoAbuseObject { |
129 | return { | 146 | return { |
130 | type: 'Flag' as 'Flag', | 147 | type: 'Flag' as 'Flag', |
131 | content: this.reason, | 148 | content: this.reason, |
diff --git a/server/models/video/video-blacklist.ts b/server/models/video/video-blacklist.ts index cdb725e7a..533bfe1ad 100644 --- a/server/models/video/video-blacklist.ts +++ b/server/models/video/video-blacklist.ts | |||
@@ -1,12 +1,14 @@ | |||
1 | import { AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' | 1 | import { AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' |
2 | import { getBlacklistSort, getSort, SortType, throwIfNotValid } from '../utils' | 2 | import { getBlacklistSort, SortType, throwIfNotValid } from '../utils' |
3 | import { ScopeNames as VideoModelScopeNames, VideoModel } from './video' | 3 | import { VideoModel } from './video' |
4 | import { ScopeNames as VideoChannelScopeNames, SummaryOptions, VideoChannelModel } from './video-channel' | 4 | import { ScopeNames as VideoChannelScopeNames, SummaryOptions, VideoChannelModel } from './video-channel' |
5 | import { isVideoBlacklistReasonValid, isVideoBlacklistTypeValid } from '../../helpers/custom-validators/video-blacklist' | 5 | import { isVideoBlacklistReasonValid, isVideoBlacklistTypeValid } from '../../helpers/custom-validators/video-blacklist' |
6 | import { VideoBlacklist, VideoBlacklistType } from '../../../shared/models/videos' | 6 | import { VideoBlacklist, VideoBlacklistType } from '../../../shared/models/videos' |
7 | import { CONSTRAINTS_FIELDS } from '../../initializers/constants' | 7 | import { CONSTRAINTS_FIELDS } from '../../initializers/constants' |
8 | import { FindOptions, literal } from 'sequelize' | 8 | import { FindOptions, literal } from 'sequelize' |
9 | import { ThumbnailModel } from './thumbnail' | 9 | import { ThumbnailModel } from './thumbnail' |
10 | import * as Bluebird from 'bluebird' | ||
11 | import { MVideoBlacklist, MVideoBlacklistFormattable } from '@server/typings/models' | ||
10 | 12 | ||
11 | @Table({ | 13 | @Table({ |
12 | tableName: 'videoBlacklist', | 14 | tableName: 'videoBlacklist', |
@@ -98,7 +100,7 @@ export class VideoBlacklistModel extends Model<VideoBlacklistModel> { | |||
98 | }) | 100 | }) |
99 | } | 101 | } |
100 | 102 | ||
101 | static loadByVideoId (id: number) { | 103 | static loadByVideoId (id: number): Bluebird<MVideoBlacklist> { |
102 | const query = { | 104 | const query = { |
103 | where: { | 105 | where: { |
104 | videoId: id | 106 | videoId: id |
@@ -108,7 +110,7 @@ export class VideoBlacklistModel extends Model<VideoBlacklistModel> { | |||
108 | return VideoBlacklistModel.findOne(query) | 110 | return VideoBlacklistModel.findOne(query) |
109 | } | 111 | } |
110 | 112 | ||
111 | toFormattedJSON (): VideoBlacklist { | 113 | toFormattedJSON (this: MVideoBlacklistFormattable): VideoBlacklist { |
112 | return { | 114 | return { |
113 | id: this.id, | 115 | id: this.id, |
114 | createdAt: this.createdAt, | 116 | createdAt: this.createdAt, |
diff --git a/server/models/video/video-caption.ts b/server/models/video/video-caption.ts index a01565851..ad5801768 100644 --- a/server/models/video/video-caption.ts +++ b/server/models/video/video-caption.ts | |||
@@ -21,6 +21,8 @@ import { join } from 'path' | |||
21 | import { logger } from '../../helpers/logger' | 21 | import { logger } from '../../helpers/logger' |
22 | import { remove } from 'fs-extra' | 22 | import { remove } from 'fs-extra' |
23 | import { CONFIG } from '../../initializers/config' | 23 | import { CONFIG } from '../../initializers/config' |
24 | import * as Bluebird from 'bluebird' | ||
25 | import { MVideoCaptionFormattable, MVideoCaptionVideo } from '@server/typings/models' | ||
24 | 26 | ||
25 | export enum ScopeNames { | 27 | export 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: { |
@@ -152,7 +154,7 @@ export class VideoCaptionModel extends Model<VideoCaptionModel> { | |||
152 | return this.Video.remote === false | 154 | return this.Video.remote === false |
153 | } | 155 | } |
154 | 156 | ||
155 | toFormattedJSON (): VideoCaption { | 157 | toFormattedJSON (this: MVideoCaptionFormattable): VideoCaption { |
156 | return { | 158 | return { |
157 | language: { | 159 | language: { |
158 | id: this.language, | 160 | id: this.language, |
@@ -162,15 +164,15 @@ export class VideoCaptionModel extends Model<VideoCaptionModel> { | |||
162 | } | 164 | } |
163 | } | 165 | } |
164 | 166 | ||
165 | getCaptionStaticPath () { | 167 | getCaptionStaticPath (this: MVideoCaptionFormattable) { |
166 | return join(LAZY_STATIC_PATHS.VIDEO_CAPTIONS, this.getCaptionName()) | 168 | return join(LAZY_STATIC_PATHS.VIDEO_CAPTIONS, this.getCaptionName()) |
167 | } | 169 | } |
168 | 170 | ||
169 | getCaptionName () { | 171 | getCaptionName (this: MVideoCaptionFormattable) { |
170 | return `${this.Video.uuid}-${this.language}.vtt` | 172 | return `${this.Video.uuid}-${this.language}.vtt` |
171 | } | 173 | } |
172 | 174 | ||
173 | removeCaptionFile () { | 175 | removeCaptionFile (this: MVideoCaptionFormattable) { |
174 | return remove(CONFIG.STORAGE.CAPTIONS_DIR + this.getCaptionName()) | 176 | return remove(CONFIG.STORAGE.CAPTIONS_DIR + this.getCaptionName()) |
175 | } | 177 | } |
176 | } | 178 | } |
diff --git a/server/models/video/video-change-ownership.ts b/server/models/video/video-change-ownership.ts index b545a2f8c..f7a351329 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' | |||
3 | import { ScopeNames as VideoScopeNames, VideoModel } from './video' | 3 | import { ScopeNames as VideoScopeNames, VideoModel } from './video' |
4 | import { VideoChangeOwnership, VideoChangeOwnershipStatus } from '../../../shared/models/videos' | 4 | import { VideoChangeOwnership, VideoChangeOwnershipStatus } from '../../../shared/models/videos' |
5 | import { getSort } from '../utils' | 5 | import { getSort } from '../utils' |
6 | import { MVideoChangeOwnershipFormattable, MVideoChangeOwnershipFull } from '@server/typings/models/video/video-change-ownership' | ||
7 | import * as Bluebird from 'bluebird' | ||
6 | 8 | ||
7 | enum ScopeNames { | 9 | enum ScopeNames { |
8 | WITH_ACCOUNTS = 'WITH_ACCOUNTS', | 10 | WITH_ACCOUNTS = 'WITH_ACCOUNTS', |
@@ -108,16 +110,16 @@ 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 | } |
119 | 121 | ||
120 | toFormattedJSON (): VideoChangeOwnership { | 122 | toFormattedJSON (this: MVideoChangeOwnershipFormattable): VideoChangeOwnership { |
121 | return { | 123 | return { |
122 | id: this.id, | 124 | id: this.id, |
123 | status: this.status, | 125 | status: this.status, |
diff --git a/server/models/video/video-channel.ts b/server/models/video/video-channel.ts index 6241a75a3..05545bd9d 100644 --- a/server/models/video/video-channel.ts +++ b/server/models/video/video-channel.ts | |||
@@ -33,6 +33,15 @@ import { ServerModel } from '../server/server' | |||
33 | import { FindOptions, ModelIndexesOptions, Op } from 'sequelize' | 33 | import { FindOptions, ModelIndexesOptions, Op } from 'sequelize' |
34 | import { AvatarModel } from '../avatar/avatar' | 34 | import { AvatarModel } from '../avatar/avatar' |
35 | import { VideoPlaylistModel } from './video-playlist' | 35 | import { VideoPlaylistModel } from './video-playlist' |
36 | import * as Bluebird from 'bluebird' | ||
37 | import { | ||
38 | MChannelAccountDefault, | ||
39 | MChannelActor, | ||
40 | MChannelActorAccountDefaultVideos, | ||
41 | MChannelAP, | ||
42 | MChannelFormattable, | ||
43 | MChannelSummaryFormattable | ||
44 | } from '../../typings/models/video' | ||
36 | 45 | ||
37 | // FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation | 46 | // FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation |
38 | const indexes: ModelIndexesOptions[] = [ | 47 | const indexes: ModelIndexesOptions[] = [ |
@@ -47,7 +56,7 @@ const indexes: ModelIndexesOptions[] = [ | |||
47 | ] | 56 | ] |
48 | 57 | ||
49 | export enum ScopeNames { | 58 | export enum ScopeNames { |
50 | AVAILABLE_FOR_LIST = 'AVAILABLE_FOR_LIST', | 59 | FOR_API = 'FOR_API', |
51 | WITH_ACCOUNT = 'WITH_ACCOUNT', | 60 | WITH_ACCOUNT = 'WITH_ACCOUNT', |
52 | WITH_ACTOR = 'WITH_ACTOR', | 61 | WITH_ACTOR = 'WITH_ACTOR', |
53 | WITH_VIDEOS = 'WITH_VIDEOS', | 62 | WITH_VIDEOS = 'WITH_VIDEOS', |
@@ -74,10 +83,10 @@ export type SummaryOptions = { | |||
74 | @Scopes(() => ({ | 83 | @Scopes(() => ({ |
75 | [ScopeNames.SUMMARY]: (options: SummaryOptions = {}) => { | 84 | [ScopeNames.SUMMARY]: (options: SummaryOptions = {}) => { |
76 | const base: FindOptions = { | 85 | const base: FindOptions = { |
77 | attributes: [ 'name', 'description', 'id', 'actorId' ], | 86 | attributes: [ 'id', 'name', 'description', 'actorId' ], |
78 | include: [ | 87 | include: [ |
79 | { | 88 | { |
80 | attributes: [ 'preferredUsername', 'url', 'serverId', 'avatarId' ], | 89 | attributes: [ 'id', 'preferredUsername', 'url', 'serverId', 'avatarId' ], |
81 | model: ActorModel.unscoped(), | 90 | model: ActorModel.unscoped(), |
82 | required: true, | 91 | required: true, |
83 | include: [ | 92 | include: [ |
@@ -106,7 +115,7 @@ export type SummaryOptions = { | |||
106 | 115 | ||
107 | return base | 116 | return base |
108 | }, | 117 | }, |
109 | [ScopeNames.AVAILABLE_FOR_LIST]: (options: AvailableForListOptions) => { | 118 | [ScopeNames.FOR_API]: (options: AvailableForListOptions) => { |
110 | // Only list local channels OR channels that are on an instance followed by actorId | 119 | // Only list local channels OR channels that are on an instance followed by actorId |
111 | const inQueryInstanceFollow = buildServerIdsFollowedBy(options.actorId) | 120 | const inQueryInstanceFollow = buildServerIdsFollowedBy(options.actorId) |
112 | 121 | ||
@@ -268,7 +277,7 @@ export class VideoChannelModel extends Model<VideoChannelModel> { | |||
268 | } | 277 | } |
269 | 278 | ||
270 | const scopes = { | 279 | const scopes = { |
271 | method: [ ScopeNames.AVAILABLE_FOR_LIST, { actorId } as AvailableForListOptions ] | 280 | method: [ ScopeNames.FOR_API, { actorId } as AvailableForListOptions ] |
272 | } | 281 | } |
273 | return VideoChannelModel | 282 | return VideoChannelModel |
274 | .scope(scopes) | 283 | .scope(scopes) |
@@ -278,7 +287,7 @@ export class VideoChannelModel extends Model<VideoChannelModel> { | |||
278 | }) | 287 | }) |
279 | } | 288 | } |
280 | 289 | ||
281 | static listLocalsForSitemap (sort: string) { | 290 | static listLocalsForSitemap (sort: string): Bluebird<MChannelActor[]> { |
282 | const query = { | 291 | const query = { |
283 | attributes: [ ], | 292 | attributes: [ ], |
284 | offset: 0, | 293 | offset: 0, |
@@ -331,7 +340,7 @@ export class VideoChannelModel extends Model<VideoChannelModel> { | |||
331 | } | 340 | } |
332 | 341 | ||
333 | const scopes = { | 342 | const scopes = { |
334 | method: [ ScopeNames.AVAILABLE_FOR_LIST, { actorId: options.actorId } as AvailableForListOptions ] | 343 | method: [ ScopeNames.FOR_API, { actorId: options.actorId } as AvailableForListOptions ] |
335 | } | 344 | } |
336 | return VideoChannelModel | 345 | return VideoChannelModel |
337 | .scope(scopes) | 346 | .scope(scopes) |
@@ -369,13 +378,13 @@ export class VideoChannelModel extends Model<VideoChannelModel> { | |||
369 | }) | 378 | }) |
370 | } | 379 | } |
371 | 380 | ||
372 | static loadByIdAndPopulateAccount (id: number) { | 381 | static loadByIdAndPopulateAccount (id: number): Bluebird<MChannelAccountDefault> { |
373 | return VideoChannelModel.unscoped() | 382 | return VideoChannelModel.unscoped() |
374 | .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ]) | 383 | .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ]) |
375 | .findByPk(id) | 384 | .findByPk(id) |
376 | } | 385 | } |
377 | 386 | ||
378 | static loadByIdAndAccount (id: number, accountId: number) { | 387 | static loadByIdAndAccount (id: number, accountId: number): Bluebird<MChannelAccountDefault> { |
379 | const query = { | 388 | const query = { |
380 | where: { | 389 | where: { |
381 | id, | 390 | id, |
@@ -388,13 +397,13 @@ export class VideoChannelModel extends Model<VideoChannelModel> { | |||
388 | .findOne(query) | 397 | .findOne(query) |
389 | } | 398 | } |
390 | 399 | ||
391 | static loadAndPopulateAccount (id: number) { | 400 | static loadAndPopulateAccount (id: number): Bluebird<MChannelAccountDefault> { |
392 | return VideoChannelModel.unscoped() | 401 | return VideoChannelModel.unscoped() |
393 | .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ]) | 402 | .scope([ ScopeNames.WITH_ACTOR, ScopeNames.WITH_ACCOUNT ]) |
394 | .findByPk(id) | 403 | .findByPk(id) |
395 | } | 404 | } |
396 | 405 | ||
397 | static loadByUrlAndPopulateAccount (url: string) { | 406 | static loadByUrlAndPopulateAccount (url: string): Bluebird<MChannelAccountDefault> { |
398 | const query = { | 407 | const query = { |
399 | include: [ | 408 | include: [ |
400 | { | 409 | { |
@@ -420,7 +429,7 @@ export class VideoChannelModel extends Model<VideoChannelModel> { | |||
420 | return VideoChannelModel.loadByNameAndHostAndPopulateAccount(name, host) | 429 | return VideoChannelModel.loadByNameAndHostAndPopulateAccount(name, host) |
421 | } | 430 | } |
422 | 431 | ||
423 | static loadLocalByNameAndPopulateAccount (name: string) { | 432 | static loadLocalByNameAndPopulateAccount (name: string): Bluebird<MChannelAccountDefault> { |
424 | const query = { | 433 | const query = { |
425 | include: [ | 434 | include: [ |
426 | { | 435 | { |
@@ -439,7 +448,7 @@ export class VideoChannelModel extends Model<VideoChannelModel> { | |||
439 | .findOne(query) | 448 | .findOne(query) |
440 | } | 449 | } |
441 | 450 | ||
442 | static loadByNameAndHostAndPopulateAccount (name: string, host: string) { | 451 | static loadByNameAndHostAndPopulateAccount (name: string, host: string): Bluebird<MChannelAccountDefault> { |
443 | const query = { | 452 | const query = { |
444 | include: [ | 453 | include: [ |
445 | { | 454 | { |
@@ -464,7 +473,7 @@ export class VideoChannelModel extends Model<VideoChannelModel> { | |||
464 | .findOne(query) | 473 | .findOne(query) |
465 | } | 474 | } |
466 | 475 | ||
467 | static loadAndPopulateAccountAndVideos (id: number) { | 476 | static loadAndPopulateAccountAndVideos (id: number): Bluebird<MChannelActorAccountDefaultVideos> { |
468 | const options = { | 477 | const options = { |
469 | include: [ | 478 | include: [ |
470 | VideoModel | 479 | VideoModel |
@@ -476,7 +485,20 @@ export class VideoChannelModel extends Model<VideoChannelModel> { | |||
476 | .findByPk(id, options) | 485 | .findByPk(id, options) |
477 | } | 486 | } |
478 | 487 | ||
479 | toFormattedJSON (): VideoChannel { | 488 | toFormattedSummaryJSON (this: MChannelSummaryFormattable): VideoChannelSummary { |
489 | const actor = this.Actor.toFormattedSummaryJSON() | ||
490 | |||
491 | return { | ||
492 | id: this.id, | ||
493 | name: actor.name, | ||
494 | displayName: this.getDisplayName(), | ||
495 | url: actor.url, | ||
496 | host: actor.host, | ||
497 | avatar: actor.avatar | ||
498 | } | ||
499 | } | ||
500 | |||
501 | toFormattedJSON (this: MChannelFormattable): VideoChannel { | ||
480 | const actor = this.Actor.toFormattedJSON() | 502 | const actor = this.Actor.toFormattedJSON() |
481 | const videoChannel = { | 503 | const videoChannel = { |
482 | id: this.id, | 504 | id: this.id, |
@@ -494,21 +516,8 @@ export class VideoChannelModel extends Model<VideoChannelModel> { | |||
494 | return Object.assign(actor, videoChannel) | 516 | return Object.assign(actor, videoChannel) |
495 | } | 517 | } |
496 | 518 | ||
497 | toFormattedSummaryJSON (): VideoChannelSummary { | 519 | toActivityPubObject (this: MChannelAP): ActivityPubActor { |
498 | const actor = this.Actor.toFormattedJSON() | 520 | const obj = this.Actor.toActivityPubObject(this.name) |
499 | |||
500 | return { | ||
501 | id: this.id, | ||
502 | name: actor.name, | ||
503 | displayName: this.getDisplayName(), | ||
504 | url: actor.url, | ||
505 | host: actor.host, | ||
506 | avatar: actor.avatar | ||
507 | } | ||
508 | } | ||
509 | |||
510 | toActivityPubObject (): ActivityPubActor { | ||
511 | const obj = this.Actor.toActivityPubObject(this.name, 'VideoChannel') | ||
512 | 521 | ||
513 | return Object.assign(obj, { | 522 | return Object.assign(obj, { |
514 | summary: this.description, | 523 | summary: this.description, |
diff --git a/server/models/video/video-comment.ts b/server/models/video/video-comment.ts index 58b75510d..2e4220434 100644 --- a/server/models/video/video-comment.ts +++ b/server/models/video/video-comment.ts | |||
@@ -1,36 +1,32 @@ | |||
1 | import { | 1 | import { 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' | ||
15 | import { ActivityTagObject } from '../../../shared/models/activitypub/objects/common-objects' | 2 | import { ActivityTagObject } from '../../../shared/models/activitypub/objects/common-objects' |
16 | import { VideoCommentObject } from '../../../shared/models/activitypub/objects/video-comment-object' | 3 | import { VideoCommentObject } from '../../../shared/models/activitypub/objects/video-comment-object' |
17 | import { VideoComment } from '../../../shared/models/videos/video-comment.model' | 4 | import { VideoComment } from '../../../shared/models/videos/video-comment.model' |
18 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' | 5 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' |
19 | import { CONSTRAINTS_FIELDS, WEBSERVER } from '../../initializers/constants' | 6 | import { CONSTRAINTS_FIELDS, WEBSERVER } from '../../initializers/constants' |
20 | import { sendDeleteVideoComment } from '../../lib/activitypub/send' | ||
21 | import { AccountModel } from '../account/account' | 7 | import { AccountModel } from '../account/account' |
22 | import { ActorModel } from '../activitypub/actor' | 8 | import { ActorModel } from '../activitypub/actor' |
23 | import { AvatarModel } from '../avatar/avatar' | ||
24 | import { ServerModel } from '../server/server' | ||
25 | import { buildBlockedAccountSQL, buildLocalAccountIdsIn, getSort, throwIfNotValid } from '../utils' | 9 | import { buildBlockedAccountSQL, buildLocalAccountIdsIn, getSort, throwIfNotValid } from '../utils' |
26 | import { VideoModel } from './video' | 10 | import { VideoModel } from './video' |
27 | import { VideoChannelModel } from './video-channel' | 11 | import { VideoChannelModel } from './video-channel' |
28 | import { getServerActor } from '../../helpers/utils' | 12 | import { getServerActor } from '../../helpers/utils' |
29 | import { UserModel } from '../account/user' | ||
30 | import { actorNameAlphabet } from '../../helpers/custom-validators/activitypub/actor' | 13 | import { actorNameAlphabet } from '../../helpers/custom-validators/activitypub/actor' |
31 | import { regexpCapture } from '../../helpers/regexp' | 14 | import { regexpCapture } from '../../helpers/regexp' |
32 | import { uniq } from 'lodash' | 15 | import { uniq } from 'lodash' |
33 | import { FindOptions, literal, Op, Order, ScopeOptions, Sequelize, Transaction } from 'sequelize' | 16 | import { FindOptions, Op, Order, ScopeOptions, Sequelize, Transaction } from 'sequelize' |
17 | import * as Bluebird from 'bluebird' | ||
18 | import { | ||
19 | MComment, | ||
20 | MCommentAP, | ||
21 | MCommentFormattable, | ||
22 | MCommentId, | ||
23 | MCommentOwner, | ||
24 | MCommentOwnerReplyVideoLight, | ||
25 | MCommentOwnerVideo, | ||
26 | MCommentOwnerVideoFeed, | ||
27 | MCommentOwnerVideoReply | ||
28 | } from '../../typings/models/video' | ||
29 | import { MUserAccountId } from '@server/typings/models' | ||
34 | 30 | ||
35 | enum ScopeNames { | 31 | enum ScopeNames { |
36 | WITH_ACCOUNT = 'WITH_ACCOUNT', | 32 | WITH_ACCOUNT = 'WITH_ACCOUNT', |
@@ -68,22 +64,7 @@ enum ScopeNames { | |||
68 | [ScopeNames.WITH_ACCOUNT]: { | 64 | [ScopeNames.WITH_ACCOUNT]: { |
69 | include: [ | 65 | include: [ |
70 | { | 66 | { |
71 | model: AccountModel, | 67 | 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 | } | 68 | } |
88 | ] | 69 | ] |
89 | }, | 70 | }, |
@@ -102,22 +83,12 @@ enum ScopeNames { | |||
102 | required: true, | 83 | required: true, |
103 | include: [ | 84 | include: [ |
104 | { | 85 | { |
105 | model: VideoChannelModel.unscoped(), | 86 | model: VideoChannelModel, |
106 | required: true, | 87 | required: true, |
107 | include: [ | 88 | include: [ |
108 | { | 89 | { |
109 | model: ActorModel, | ||
110 | required: true | ||
111 | }, | ||
112 | { | ||
113 | model: AccountModel, | 90 | model: AccountModel, |
114 | required: true, | 91 | required: true |
115 | include: [ | ||
116 | { | ||
117 | model: ActorModel, | ||
118 | required: true | ||
119 | } | ||
120 | ] | ||
121 | } | 92 | } |
122 | ] | 93 | ] |
123 | } | 94 | } |
@@ -212,7 +183,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
212 | }) | 183 | }) |
213 | Account: AccountModel | 184 | Account: AccountModel |
214 | 185 | ||
215 | static loadById (id: number, t?: Transaction) { | 186 | static loadById (id: number, t?: Transaction): Bluebird<MComment> { |
216 | const query: FindOptions = { | 187 | const query: FindOptions = { |
217 | where: { | 188 | where: { |
218 | id | 189 | id |
@@ -224,7 +195,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
224 | return VideoCommentModel.findOne(query) | 195 | return VideoCommentModel.findOne(query) |
225 | } | 196 | } |
226 | 197 | ||
227 | static loadByIdAndPopulateVideoAndAccountAndReply (id: number, t?: Transaction) { | 198 | static loadByIdAndPopulateVideoAndAccountAndReply (id: number, t?: Transaction): Bluebird<MCommentOwnerVideoReply> { |
228 | const query: FindOptions = { | 199 | const query: FindOptions = { |
229 | where: { | 200 | where: { |
230 | id | 201 | id |
@@ -238,7 +209,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
238 | .findOne(query) | 209 | .findOne(query) |
239 | } | 210 | } |
240 | 211 | ||
241 | static loadByUrlAndPopulateAccountAndVideo (url: string, t?: Transaction) { | 212 | static loadByUrlAndPopulateAccountAndVideo (url: string, t?: Transaction): Bluebird<MCommentOwnerVideo> { |
242 | const query: FindOptions = { | 213 | const query: FindOptions = { |
243 | where: { | 214 | where: { |
244 | url | 215 | url |
@@ -250,7 +221,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
250 | return VideoCommentModel.scope([ ScopeNames.WITH_ACCOUNT, ScopeNames.WITH_VIDEO ]).findOne(query) | 221 | return VideoCommentModel.scope([ ScopeNames.WITH_ACCOUNT, ScopeNames.WITH_VIDEO ]).findOne(query) |
251 | } | 222 | } |
252 | 223 | ||
253 | static loadByUrlAndPopulateReplyAndVideoUrlAndAccount (url: string, t?: Transaction) { | 224 | static loadByUrlAndPopulateReplyAndVideoUrlAndAccount (url: string, t?: Transaction): Bluebird<MCommentOwnerReplyVideoLight> { |
254 | const query: FindOptions = { | 225 | const query: FindOptions = { |
255 | where: { | 226 | where: { |
256 | url | 227 | url |
@@ -273,7 +244,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
273 | start: number, | 244 | start: number, |
274 | count: number, | 245 | count: number, |
275 | sort: string, | 246 | sort: string, |
276 | user?: UserModel | 247 | user?: MUserAccountId |
277 | }) { | 248 | }) { |
278 | const { videoId, start, count, sort, user } = parameters | 249 | const { videoId, start, count, sort, user } = parameters |
279 | 250 | ||
@@ -314,7 +285,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
314 | static async listThreadCommentsForApi (parameters: { | 285 | static async listThreadCommentsForApi (parameters: { |
315 | videoId: number, | 286 | videoId: number, |
316 | threadId: number, | 287 | threadId: number, |
317 | user?: UserModel | 288 | user?: MUserAccountId |
318 | }) { | 289 | }) { |
319 | const { videoId, threadId, user } = parameters | 290 | const { videoId, threadId, user } = parameters |
320 | 291 | ||
@@ -353,7 +324,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
353 | }) | 324 | }) |
354 | } | 325 | } |
355 | 326 | ||
356 | static listThreadParentComments (comment: VideoCommentModel, t: Transaction, order: 'ASC' | 'DESC' = 'ASC') { | 327 | static listThreadParentComments (comment: MCommentId, t: Transaction, order: 'ASC' | 'DESC' = 'ASC'): Bluebird<MCommentOwner[]> { |
357 | const query = { | 328 | const query = { |
358 | order: [ [ 'createdAt', order ] ] as Order, | 329 | order: [ [ 'createdAt', order ] ] as Order, |
359 | where: { | 330 | where: { |
@@ -389,10 +360,10 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
389 | transaction: t | 360 | transaction: t |
390 | } | 361 | } |
391 | 362 | ||
392 | return VideoCommentModel.findAndCountAll(query) | 363 | return VideoCommentModel.findAndCountAll<MComment>(query) |
393 | } | 364 | } |
394 | 365 | ||
395 | static listForFeed (start: number, count: number, videoId?: number) { | 366 | static listForFeed (start: number, count: number, videoId?: number): Bluebird<MCommentOwnerVideoFeed[]> { |
396 | const query = { | 367 | const query = { |
397 | order: [ [ 'createdAt', 'DESC' ] ] as Order, | 368 | order: [ [ 'createdAt', 'DESC' ] ] as Order, |
398 | offset: start, | 369 | offset: start, |
@@ -506,7 +477,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
506 | return uniq(result) | 477 | return uniq(result) |
507 | } | 478 | } |
508 | 479 | ||
509 | toFormattedJSON () { | 480 | toFormattedJSON (this: MCommentFormattable) { |
510 | return { | 481 | return { |
511 | id: this.id, | 482 | id: this.id, |
512 | url: this.url, | 483 | url: this.url, |
@@ -521,7 +492,7 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
521 | } as VideoComment | 492 | } as VideoComment |
522 | } | 493 | } |
523 | 494 | ||
524 | toActivityPubObject (threadParentComments: VideoCommentModel[]): VideoCommentObject { | 495 | toActivityPubObject (this: MCommentAP, threadParentComments: MCommentOwner[]): VideoCommentObject { |
525 | let inReplyTo: string | 496 | let inReplyTo: string |
526 | // New thread, so in AS we reply to the video | 497 | // New thread, so in AS we reply to the video |
527 | if (this.inReplyToCommentId === null) { | 498 | 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' | |||
25 | import { VideoStreamingPlaylistModel } from './video-streaming-playlist' | 25 | import { VideoStreamingPlaylistModel } from './video-streaming-playlist' |
26 | import { FindOptions, QueryTypes, Transaction } from 'sequelize' | 26 | import { FindOptions, QueryTypes, Transaction } from 'sequelize' |
27 | import { MIMETYPES } from '../../initializers/constants' | 27 | import { MIMETYPES } from '../../initializers/constants' |
28 | import { 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..2987aa780 100644 --- a/server/models/video/video-format-utils.ts +++ b/server/models/video/video-format-utils.ts | |||
@@ -1,6 +1,5 @@ | |||
1 | import { Video, VideoDetails, VideoFile } from '../../../shared/models/videos' | 1 | import { Video, VideoDetails, VideoFile } from '../../../shared/models/videos' |
2 | import { VideoModel } from './video' | 2 | import { VideoModel } from './video' |
3 | import { VideoFileModel } from './video-file' | ||
4 | import { | 3 | import { |
5 | ActivityPlaylistInfohashesObject, | 4 | ActivityPlaylistInfohashesObject, |
6 | ActivityPlaylistSegmentHashesObject, | 5 | ActivityPlaylistSegmentHashesObject, |
@@ -17,7 +16,9 @@ import { | |||
17 | } from '../../lib/activitypub' | 16 | } from '../../lib/activitypub' |
18 | import { isArray } from '../../helpers/custom-validators/misc' | 17 | import { isArray } from '../../helpers/custom-validators/misc' |
19 | import { VideoStreamingPlaylist } from '../../../shared/models/videos/video-streaming-playlist.model' | 18 | import { VideoStreamingPlaylist } from '../../../shared/models/videos/video-streaming-playlist.model' |
20 | import { VideoStreamingPlaylistModel } from './video-streaming-playlist' | 19 | import { MStreamingPlaylistRedundanciesOpt, MVideo, MVideoAP, MVideoFormattable, MVideoFormattableDetails } from '../../typings/models' |
20 | import { MStreamingPlaylistRedundancies } from '../../typings/models/video/video-streaming-playlist' | ||
21 | import { MVideoFileRedundanciesOpt } from '../../typings/models/video/video-file' | ||
21 | 22 | ||
22 | export type VideoFormattingJSONOptions = { | 23 | export type VideoFormattingJSONOptions = { |
23 | completeDescription?: boolean | 24 | completeDescription?: boolean |
@@ -28,7 +29,7 @@ export type VideoFormattingJSONOptions = { | |||
28 | blacklistInfo?: boolean | 29 | blacklistInfo?: boolean |
29 | } | 30 | } |
30 | } | 31 | } |
31 | function videoModelToFormattedJSON (video: VideoModel, options?: VideoFormattingJSONOptions): Video { | 32 | function videoModelToFormattedJSON (video: MVideoFormattable, options?: VideoFormattingJSONOptions): Video { |
32 | const userHistory = isArray(video.UserVideoHistories) ? video.UserVideoHistories[0] : undefined | 33 | const userHistory = isArray(video.UserVideoHistories) ? video.UserVideoHistories[0] : undefined |
33 | 34 | ||
34 | const videoObject: Video = { | 35 | const videoObject: Video = { |
@@ -102,7 +103,7 @@ function videoModelToFormattedJSON (video: VideoModel, options?: VideoFormatting | |||
102 | return videoObject | 103 | return videoObject |
103 | } | 104 | } |
104 | 105 | ||
105 | function videoModelToFormattedDetailsJSON (video: VideoModel): VideoDetails { | 106 | function videoModelToFormattedDetailsJSON (video: MVideoFormattableDetails): 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 | ||
145 | function streamingPlaylistsModelToFormattedJSON (video: VideoModel, playlists: VideoStreamingPlaylistModel[]): VideoStreamingPlaylist[] { | 146 | function streamingPlaylistsModelToFormattedJSON (playlists: MStreamingPlaylistRedundanciesOpt[]): 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 | ||
164 | function videoFilesModelToFormattedJSON (video: VideoModel, videoFiles: VideoFileModel[]): VideoFile[] { | 165 | function 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 | ||
192 | function videoModelToActivityPubObject (video: VideoModel): VideoTorrentObject { | 193 | function 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..af5314ce9 100644 --- a/server/models/video/video-import.ts +++ b/server/models/video/video-import.ts | |||
@@ -20,6 +20,8 @@ import { isVideoImportStateValid, isVideoImportTargetUrlValid } from '../../help | |||
20 | import { VideoImport, VideoImportState } from '../../../shared' | 20 | import { VideoImport, VideoImportState } from '../../../shared' |
21 | import { isVideoMagnetUriValid } from '../../helpers/custom-validators/videos' | 21 | import { isVideoMagnetUriValid } from '../../helpers/custom-validators/videos' |
22 | import { UserModel } from '../account/user' | 22 | import { UserModel } from '../account/user' |
23 | import * as Bluebird from 'bluebird' | ||
24 | import { MVideoImportDefault, MVideoImportFormattable } 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, |
@@ -148,7 +154,7 @@ export class VideoImportModel extends Model<VideoImportModel> { | |||
148 | return this.targetUrl || this.magnetUri || this.torrentName | 154 | return this.targetUrl || this.magnetUri || this.torrentName |
149 | } | 155 | } |
150 | 156 | ||
151 | toFormattedJSON (): VideoImport { | 157 | toFormattedJSON (this: MVideoImportFormattable): VideoImport { |
152 | const videoFormatOptions = { | 158 | const videoFormatOptions = { |
153 | completeDescription: true, | 159 | completeDescription: true, |
154 | additionalAttributes: { state: true, waitTranscoding: true, scheduledUpdate: true } | 160 | additionalAttributes: { state: true, waitTranscoding: true, scheduledUpdate: true } |
diff --git a/server/models/video/video-playlist-element.ts b/server/models/video/video-playlist-element.ts index dd7653533..a28021313 100644 --- a/server/models/video/video-playlist-element.ts +++ b/server/models/video/video-playlist-element.ts | |||
@@ -21,10 +21,18 @@ import { CONSTRAINTS_FIELDS } from '../../initializers/constants' | |||
21 | import { PlaylistElementObject } from '../../../shared/models/activitypub/objects/playlist-element-object' | 21 | import { PlaylistElementObject } from '../../../shared/models/activitypub/objects/playlist-element-object' |
22 | import * as validator from 'validator' | 22 | import * as validator from 'validator' |
23 | import { AggregateOptions, Op, ScopeOptions, Sequelize, Transaction } from 'sequelize' | 23 | import { AggregateOptions, Op, ScopeOptions, Sequelize, Transaction } from 'sequelize' |
24 | import { UserModel } from '../account/user' | ||
25 | import { VideoPlaylistElement, VideoPlaylistElementType } from '../../../shared/models/videos/playlist/video-playlist-element.model' | 24 | import { VideoPlaylistElement, VideoPlaylistElementType } from '../../../shared/models/videos/playlist/video-playlist-element.model' |
26 | import { AccountModel } from '../account/account' | 25 | import { AccountModel } from '../account/account' |
27 | import { VideoPrivacy } from '../../../shared/models/videos' | 26 | import { VideoPrivacy } from '../../../shared/models/videos' |
27 | import * as Bluebird from 'bluebird' | ||
28 | import { | ||
29 | MVideoPlaylistElement, | ||
30 | MVideoPlaylistElementAP, | ||
31 | MVideoPlaylistElementFormattable, | ||
32 | MVideoPlaylistElementVideoUrlPlaylistPrivacy, | ||
33 | MVideoPlaylistVideoThumbnail | ||
34 | } from '@server/typings/models/video/video-playlist-element' | ||
35 | import { MUserAccountId } from '@server/typings/models' | ||
28 | 36 | ||
29 | @Table({ | 37 | @Table({ |
30 | tableName: 'videoPlaylistElement', | 38 | tableName: 'videoPlaylistElement', |
@@ -116,7 +124,7 @@ export class VideoPlaylistElementModel extends Model<VideoPlaylistElementModel> | |||
116 | count: number, | 124 | count: number, |
117 | videoPlaylistId: number, | 125 | videoPlaylistId: number, |
118 | serverAccount: AccountModel, | 126 | serverAccount: AccountModel, |
119 | user?: UserModel | 127 | user?: MUserAccountId |
120 | }) { | 128 | }) { |
121 | const accountIds = [ options.serverAccount.id ] | 129 | const accountIds = [ options.serverAccount.id ] |
122 | const videoScope: (ScopeOptions | string)[] = [ | 130 | const videoScope: (ScopeOptions | string)[] = [ |
@@ -162,7 +170,7 @@ export class VideoPlaylistElementModel extends Model<VideoPlaylistElementModel> | |||
162 | ]).then(([ total, data ]) => ({ total, data })) | 170 | ]).then(([ total, data ]) => ({ total, data })) |
163 | } | 171 | } |
164 | 172 | ||
165 | static loadByPlaylistAndVideo (videoPlaylistId: number, videoId: number) { | 173 | static loadByPlaylistAndVideo (videoPlaylistId: number, videoId: number): Bluebird<MVideoPlaylistElement> { |
166 | const query = { | 174 | const query = { |
167 | where: { | 175 | where: { |
168 | videoPlaylistId, | 176 | videoPlaylistId, |
@@ -173,11 +181,14 @@ export class VideoPlaylistElementModel extends Model<VideoPlaylistElementModel> | |||
173 | return VideoPlaylistElementModel.findOne(query) | 181 | return VideoPlaylistElementModel.findOne(query) |
174 | } | 182 | } |
175 | 183 | ||
176 | static loadById (playlistElementId: number) { | 184 | static loadById (playlistElementId: number): Bluebird<MVideoPlaylistElement> { |
177 | return VideoPlaylistElementModel.findByPk(playlistElementId) | 185 | return VideoPlaylistElementModel.findByPk(playlistElementId) |
178 | } | 186 | } |
179 | 187 | ||
180 | static loadByPlaylistAndVideoForAP (playlistId: number | string, videoId: number | string) { | 188 | static loadByPlaylistAndVideoForAP ( |
189 | playlistId: number | string, | ||
190 | videoId: number | string | ||
191 | ): Bluebird<MVideoPlaylistElementVideoUrlPlaylistPrivacy> { | ||
181 | const playlistWhere = validator.isUUID('' + playlistId) ? { uuid: playlistId } : { id: playlistId } | 192 | const playlistWhere = validator.isUUID('' + playlistId) ? { uuid: playlistId } : { id: playlistId } |
182 | const videoWhere = validator.isUUID('' + videoId) ? { uuid: videoId } : { id: videoId } | 193 | const videoWhere = validator.isUUID('' + videoId) ? { uuid: videoId } : { id: videoId } |
183 | 194 | ||
@@ -218,7 +229,7 @@ export class VideoPlaylistElementModel extends Model<VideoPlaylistElementModel> | |||
218 | }) | 229 | }) |
219 | } | 230 | } |
220 | 231 | ||
221 | static loadFirstElementWithVideoThumbnail (videoPlaylistId: number) { | 232 | static loadFirstElementWithVideoThumbnail (videoPlaylistId: number): Bluebird<MVideoPlaylistVideoThumbnail> { |
222 | const query = { | 233 | const query = { |
223 | order: getSort('position'), | 234 | order: getSort('position'), |
224 | where: { | 235 | where: { |
@@ -290,7 +301,7 @@ export class VideoPlaylistElementModel extends Model<VideoPlaylistElementModel> | |||
290 | return VideoPlaylistElementModel.increment({ position: by }, query) | 301 | return VideoPlaylistElementModel.increment({ position: by }, query) |
291 | } | 302 | } |
292 | 303 | ||
293 | getType (displayNSFW?: boolean, accountId?: number) { | 304 | getType (this: MVideoPlaylistElementFormattable, displayNSFW?: boolean, accountId?: number) { |
294 | const video = this.Video | 305 | const video = this.Video |
295 | 306 | ||
296 | if (!video) return VideoPlaylistElementType.DELETED | 307 | if (!video) return VideoPlaylistElementType.DELETED |
@@ -306,14 +317,17 @@ export class VideoPlaylistElementModel extends Model<VideoPlaylistElementModel> | |||
306 | return VideoPlaylistElementType.REGULAR | 317 | return VideoPlaylistElementType.REGULAR |
307 | } | 318 | } |
308 | 319 | ||
309 | getVideoElement (displayNSFW?: boolean, accountId?: number) { | 320 | getVideoElement (this: MVideoPlaylistElementFormattable, displayNSFW?: boolean, accountId?: number) { |
310 | if (!this.Video) return null | 321 | if (!this.Video) return null |
311 | if (this.getType(displayNSFW, accountId) !== VideoPlaylistElementType.REGULAR) return null | 322 | if (this.getType(displayNSFW, accountId) !== VideoPlaylistElementType.REGULAR) return null |
312 | 323 | ||
313 | return this.Video.toFormattedJSON() | 324 | return this.Video.toFormattedJSON() |
314 | } | 325 | } |
315 | 326 | ||
316 | toFormattedJSON (options: { displayNSFW?: boolean, accountId?: number } = {}): VideoPlaylistElement { | 327 | toFormattedJSON ( |
328 | this: MVideoPlaylistElementFormattable, | ||
329 | options: { displayNSFW?: boolean, accountId?: number } = {} | ||
330 | ): VideoPlaylistElement { | ||
317 | return { | 331 | return { |
318 | id: this.id, | 332 | id: this.id, |
319 | position: this.position, | 333 | position: this.position, |
@@ -326,7 +340,7 @@ export class VideoPlaylistElementModel extends Model<VideoPlaylistElementModel> | |||
326 | } | 340 | } |
327 | } | 341 | } |
328 | 342 | ||
329 | toActivityPubObject (): PlaylistElementObject { | 343 | toActivityPubObject (this: MVideoPlaylistElementAP): PlaylistElementObject { |
330 | const base: PlaylistElementObject = { | 344 | const base: PlaylistElementObject = { |
331 | id: this.url, | 345 | id: this.url, |
332 | type: 'PlaylistElement', | 346 | type: 'PlaylistElement', |
diff --git a/server/models/video/video-playlist.ts b/server/models/video/video-playlist.ts index c8e97c491..278d80ac0 100644 --- a/server/models/video/video-playlist.ts +++ b/server/models/video/video-playlist.ts | |||
@@ -43,6 +43,15 @@ import { VideoPlaylistType } from '../../../shared/models/videos/playlist/video- | |||
43 | import { ThumbnailModel } from './thumbnail' | 43 | import { ThumbnailModel } from './thumbnail' |
44 | import { ActivityIconObject } from '../../../shared/models/activitypub/objects' | 44 | import { ActivityIconObject } from '../../../shared/models/activitypub/objects' |
45 | import { FindOptions, literal, Op, ScopeOptions, Transaction, WhereOptions } from 'sequelize' | 45 | import { FindOptions, literal, Op, ScopeOptions, Transaction, WhereOptions } from 'sequelize' |
46 | import * as Bluebird from 'bluebird' | ||
47 | import { | ||
48 | MVideoPlaylistAccountThumbnail, MVideoPlaylistAP, | ||
49 | MVideoPlaylistFormattable, | ||
50 | MVideoPlaylistFull, | ||
51 | MVideoPlaylistFullSummary, | ||
52 | MVideoPlaylistIdWithElements | ||
53 | } from '../../typings/models/video/video-playlist' | ||
54 | import { MThumbnail } from '../../typings/models/video/thumbnail' | ||
46 | 55 | ||
47 | enum ScopeNames { | 56 | enum ScopeNames { |
48 | AVAILABLE_FOR_LIST = 'AVAILABLE_FOR_LIST', | 57 | AVAILABLE_FOR_LIST = 'AVAILABLE_FOR_LIST', |
@@ -332,7 +341,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> { | |||
332 | }) | 341 | }) |
333 | } | 342 | } |
334 | 343 | ||
335 | static listPlaylistIdsOf (accountId: number, videoIds: number[]) { | 344 | static listPlaylistIdsOf (accountId: number, videoIds: number[]): Bluebird<MVideoPlaylistIdWithElements[]> { |
336 | const query = { | 345 | const query = { |
337 | attributes: [ 'id' ], | 346 | attributes: [ 'id' ], |
338 | where: { | 347 | where: { |
@@ -368,7 +377,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> { | |||
368 | .then(e => !!e) | 377 | .then(e => !!e) |
369 | } | 378 | } |
370 | 379 | ||
371 | static loadWithAccountAndChannelSummary (id: number | string, transaction: Transaction) { | 380 | static loadWithAccountAndChannelSummary (id: number | string, transaction: Transaction): Bluebird<MVideoPlaylistFullSummary> { |
372 | const where = buildWhereIdOrUUID(id) | 381 | const where = buildWhereIdOrUUID(id) |
373 | 382 | ||
374 | const query = { | 383 | const query = { |
@@ -381,7 +390,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> { | |||
381 | .findOne(query) | 390 | .findOne(query) |
382 | } | 391 | } |
383 | 392 | ||
384 | static loadWithAccountAndChannel (id: number | string, transaction: Transaction) { | 393 | static loadWithAccountAndChannel (id: number | string, transaction: Transaction): Bluebird<MVideoPlaylistFull> { |
385 | const where = buildWhereIdOrUUID(id) | 394 | const where = buildWhereIdOrUUID(id) |
386 | 395 | ||
387 | const query = { | 396 | const query = { |
@@ -394,7 +403,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> { | |||
394 | .findOne(query) | 403 | .findOne(query) |
395 | } | 404 | } |
396 | 405 | ||
397 | static loadByUrlAndPopulateAccount (url: string) { | 406 | static loadByUrlAndPopulateAccount (url: string): Bluebird<MVideoPlaylistAccountThumbnail> { |
398 | const query = { | 407 | const query = { |
399 | where: { | 408 | where: { |
400 | url | 409 | url |
@@ -423,7 +432,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> { | |||
423 | return VideoPlaylistModel.update({ privacy: VideoPlaylistPrivacy.PRIVATE, videoChannelId: null }, query) | 432 | return VideoPlaylistModel.update({ privacy: VideoPlaylistPrivacy.PRIVATE, videoChannelId: null }, query) |
424 | } | 433 | } |
425 | 434 | ||
426 | async setAndSaveThumbnail (thumbnail: ThumbnailModel, t: Transaction) { | 435 | async setAndSaveThumbnail (thumbnail: MThumbnail, t: Transaction) { |
427 | thumbnail.videoPlaylistId = this.id | 436 | thumbnail.videoPlaylistId = this.id |
428 | 437 | ||
429 | this.Thumbnail = await thumbnail.save({ transaction: t }) | 438 | this.Thumbnail = await thumbnail.save({ transaction: t }) |
@@ -471,7 +480,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> { | |||
471 | return isOutdated(this, ACTIVITY_PUB.VIDEO_PLAYLIST_REFRESH_INTERVAL) | 480 | return isOutdated(this, ACTIVITY_PUB.VIDEO_PLAYLIST_REFRESH_INTERVAL) |
472 | } | 481 | } |
473 | 482 | ||
474 | toFormattedJSON (): VideoPlaylist { | 483 | toFormattedJSON (this: MVideoPlaylistFormattable): VideoPlaylist { |
475 | return { | 484 | return { |
476 | id: this.id, | 485 | id: this.id, |
477 | uuid: this.uuid, | 486 | uuid: this.uuid, |
@@ -501,7 +510,7 @@ export class VideoPlaylistModel extends Model<VideoPlaylistModel> { | |||
501 | } | 510 | } |
502 | } | 511 | } |
503 | 512 | ||
504 | toActivityPubObject (page: number, t: Transaction): Promise<PlaylistObject> { | 513 | toActivityPubObject (this: MVideoPlaylistAP, page: number, t: Transaction): Promise<PlaylistObject> { |
505 | const handler = (start: number, count: number) => { | 514 | const handler = (start: number, count: number) => { |
506 | return VideoPlaylistElementModel.listUrlsOfForAP(this.id, start, count, t) | 515 | return VideoPlaylistElementModel.listUrlsOfForAP(this.id, start, count, t) |
507 | } | 516 | } |
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' | |||
8 | import { VideoModel } from './video' | 8 | import { VideoModel } from './video' |
9 | import { VideoChannelModel } from './video-channel' | 9 | import { VideoChannelModel } from './video-channel' |
10 | import { Op, Transaction } from 'sequelize' | 10 | import { Op, Transaction } from 'sequelize' |
11 | import { MVideoShareActor, MVideoShareFull } from '../../typings/models/video' | ||
12 | import { MActorDefault } from '../../typings/models' | ||
11 | 13 | ||
12 | enum ScopeNames { | 14 | enum 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 @@ | |||
1 | import { AllowNull, BelongsTo, Column, CreatedAt, ForeignKey, HasMany, Is, Model, Table, UpdatedAt, DataType } from 'sequelize-typescript' | 1 | import { AllowNull, BelongsTo, Column, CreatedAt, DataType, ForeignKey, HasMany, Is, Model, Table, UpdatedAt } from 'sequelize-typescript' |
2 | import { isVideoFileInfoHashValid } from '../../helpers/custom-validators/videos' | 2 | import { isVideoFileInfoHashValid } from '../../helpers/custom-validators/videos' |
3 | import { throwIfNotValid } from '../utils' | 3 | import { throwIfNotValid } from '../utils' |
4 | import { VideoModel } from './video' | 4 | import { VideoModel } from './video' |
5 | import { VideoRedundancyModel } from '../redundancy/video-redundancy' | 5 | import { VideoRedundancyModel } from '../redundancy/video-redundancy' |
6 | import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type' | 6 | import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type' |
7 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' | 7 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' |
8 | import { CONSTRAINTS_FIELDS, STATIC_PATHS, P2P_MEDIA_LOADER_PEER_VERSION } from '../../initializers/constants' | 8 | import { CONSTRAINTS_FIELDS, P2P_MEDIA_LOADER_PEER_VERSION, STATIC_PATHS } from '../../initializers/constants' |
9 | import { VideoFileModel } from './video-file' | ||
10 | import { join } from 'path' | 9 | import { join } from 'path' |
11 | import { sha1 } from '../../helpers/core-utils' | 10 | import { sha1 } from '../../helpers/core-utils' |
12 | import { isArrayOf } from '../../helpers/custom-validators/misc' | 11 | import { isArrayOf } from '../../helpers/custom-validators/misc' |
13 | import { QueryTypes, Op } from 'sequelize' | 12 | import { Op, QueryTypes } from 'sequelize' |
13 | import { 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..6856dcd9f 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' |
39 | import { UserRight, VideoPrivacy, VideoResolution, VideoState } from '../../../shared' | 39 | import { UserRight, VideoPrivacy, VideoState } from '../../../shared' |
40 | import { VideoTorrentObject } from '../../../shared/models/activitypub/objects' | 40 | import { VideoTorrentObject } from '../../../shared/models/activitypub/objects' |
41 | import { Video, VideoDetails, VideoFile } from '../../../shared/models/videos' | 41 | import { Video, VideoDetails, VideoFile } from '../../../shared/models/videos' |
42 | import { VideoFilter } from '../../../shared/models/videos/video-query.type' | 42 | import { 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' |
113 | import { UserVideoHistoryModel } from '../account/user-video-history' | 113 | import { UserVideoHistoryModel } from '../account/user-video-history' |
114 | import { UserModel } from '../account/user' | ||
115 | import { VideoImportModel } from './video-import' | 114 | import { VideoImportModel } from './video-import' |
116 | import { VideoStreamingPlaylistModel } from './video-streaming-playlist' | 115 | import { VideoStreamingPlaylistModel } from './video-streaming-playlist' |
117 | import { VideoPlaylistElementModel } from './video-playlist-element' | 116 | import { VideoPlaylistElementModel } from './video-playlist-element' |
@@ -120,6 +119,29 @@ import { ThumbnailModel } from './thumbnail' | |||
120 | import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type' | 119 | import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type' |
121 | import { createTorrentPromise } from '../../helpers/webtorrent' | 120 | import { createTorrentPromise } from '../../helpers/webtorrent' |
122 | import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type' | 121 | import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type' |
122 | import { | ||
123 | MChannel, | ||
124 | MChannelAccountDefault, | ||
125 | MChannelId, | ||
126 | MUserAccountId, | ||
127 | MUserId, | ||
128 | MVideoAccountLight, | ||
129 | MVideoAccountLightBlacklistAllFiles, | ||
130 | MVideoAP, | ||
131 | MVideoDetails, | ||
132 | MVideoFormattable, | ||
133 | MVideoFormattableDetails, | ||
134 | MVideoForUser, | ||
135 | MVideoFullLight, | ||
136 | MVideoIdThumbnail, | ||
137 | MVideoThumbnail, | ||
138 | MVideoThumbnailBlacklist, | ||
139 | MVideoWithAllFiles, | ||
140 | MVideoWithFile, | ||
141 | MVideoWithRights | ||
142 | } from '../../typings/models' | ||
143 | import { MVideoFile, MVideoFileRedundanciesOpt } from '../../typings/models/video/video-file' | ||
144 | import { MThumbnail } from '../../typings/models/video/thumbnail' | ||
123 | 145 | ||
124 | // FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation | 146 | // FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation |
125 | const indexes: (ModelIndexesOptions & { where?: WhereOptions })[] = [ | 147 | const indexes: (ModelIndexesOptions & { where?: WhereOptions })[] = [ |
@@ -232,8 +254,8 @@ export type AvailableForListIDsOptions = { | |||
232 | videoPlaylistId?: number | 254 | videoPlaylistId?: number |
233 | 255 | ||
234 | trendingDays?: number | 256 | trendingDays?: number |
235 | user?: UserModel, | 257 | user?: MUserAccountId |
236 | historyOfUser?: UserModel | 258 | historyOfUser?: MUserId |
237 | 259 | ||
238 | baseWhere?: WhereOptions[] | 260 | baseWhere?: WhereOptions[] |
239 | } | 261 | } |
@@ -446,13 +468,15 @@ export type AvailableForListIDsOptions = { | |||
446 | // FIXME: issues with sequelize count when making a join on n:m relation, so we just make a IN() | 468 | // FIXME: issues with sequelize count when making a join on n:m relation, so we just make a IN() |
447 | if (options.tagsAllOf || options.tagsOneOf) { | 469 | if (options.tagsAllOf || options.tagsOneOf) { |
448 | if (options.tagsOneOf) { | 470 | if (options.tagsOneOf) { |
471 | const tagsOneOfLower = options.tagsOneOf.map(t => t.toLowerCase()) | ||
472 | |||
449 | whereAnd.push({ | 473 | whereAnd.push({ |
450 | id: { | 474 | id: { |
451 | [ Op.in ]: Sequelize.literal( | 475 | [ Op.in ]: Sequelize.literal( |
452 | '(' + | 476 | '(' + |
453 | 'SELECT "videoId" FROM "videoTag" ' + | 477 | 'SELECT "videoId" FROM "videoTag" ' + |
454 | 'INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' + | 478 | 'INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' + |
455 | 'WHERE "tag"."name" IN (' + createSafeIn(VideoModel, options.tagsOneOf) + ')' + | 479 | 'WHERE lower("tag"."name") IN (' + createSafeIn(VideoModel, tagsOneOfLower) + ')' + |
456 | ')' | 480 | ')' |
457 | ) | 481 | ) |
458 | } | 482 | } |
@@ -460,14 +484,16 @@ export type AvailableForListIDsOptions = { | |||
460 | } | 484 | } |
461 | 485 | ||
462 | if (options.tagsAllOf) { | 486 | if (options.tagsAllOf) { |
487 | const tagsAllOfLower = options.tagsAllOf.map(t => t.toLowerCase()) | ||
488 | |||
463 | whereAnd.push({ | 489 | whereAnd.push({ |
464 | id: { | 490 | id: { |
465 | [ Op.in ]: Sequelize.literal( | 491 | [ Op.in ]: Sequelize.literal( |
466 | '(' + | 492 | '(' + |
467 | 'SELECT "videoId" FROM "videoTag" ' + | 493 | 'SELECT "videoId" FROM "videoTag" ' + |
468 | 'INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' + | 494 | 'INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' + |
469 | 'WHERE "tag"."name" IN (' + createSafeIn(VideoModel, options.tagsAllOf) + ')' + | 495 | 'WHERE lower("tag"."name") IN (' + createSafeIn(VideoModel, tagsAllOfLower) + ')' + |
470 | 'GROUP BY "videoTag"."videoId" HAVING COUNT(*) = ' + options.tagsAllOf.length + | 496 | 'GROUP BY "videoTag"."videoId" HAVING COUNT(*) = ' + tagsAllOfLower.length + |
471 | ')' | 497 | ')' |
472 | ) | 498 | ) |
473 | } | 499 | } |
@@ -634,7 +660,7 @@ export type AvailableForListIDsOptions = { | |||
634 | [ ScopeNames.WITH_BLACKLISTED ]: { | 660 | [ ScopeNames.WITH_BLACKLISTED ]: { |
635 | include: [ | 661 | include: [ |
636 | { | 662 | { |
637 | attributes: [ 'id', 'reason' ], | 663 | attributes: [ 'id', 'reason', 'unfederated' ], |
638 | model: VideoBlacklistModel, | 664 | model: VideoBlacklistModel, |
639 | required: false | 665 | required: false |
640 | } | 666 | } |
@@ -989,18 +1015,16 @@ export class VideoModel extends Model<VideoModel> { | |||
989 | VideoCaptions: VideoCaptionModel[] | 1015 | VideoCaptions: VideoCaptionModel[] |
990 | 1016 | ||
991 | @BeforeDestroy | 1017 | @BeforeDestroy |
992 | static async sendDelete (instance: VideoModel, options) { | 1018 | static async sendDelete (instance: MVideoAccountLight, options) { |
993 | if (instance.isOwned()) { | 1019 | if (instance.isOwned()) { |
994 | if (!instance.VideoChannel) { | 1020 | if (!instance.VideoChannel) { |
995 | instance.VideoChannel = await instance.$get('VideoChannel', { | 1021 | instance.VideoChannel = await instance.$get('VideoChannel', { |
996 | include: [ | 1022 | include: [ |
997 | { | 1023 | ActorModel, |
998 | model: AccountModel, | 1024 | AccountModel |
999 | include: [ ActorModel ] | ||
1000 | } | ||
1001 | ], | 1025 | ], |
1002 | transaction: options.transaction | 1026 | transaction: options.transaction |
1003 | }) as VideoChannelModel | 1027 | }) as MChannelAccountDefault |
1004 | } | 1028 | } |
1005 | 1029 | ||
1006 | return sendDeleteVideo(instance, options.transaction) | 1030 | return sendDeleteVideo(instance, options.transaction) |
@@ -1039,7 +1063,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1039 | return undefined | 1063 | return undefined |
1040 | } | 1064 | } |
1041 | 1065 | ||
1042 | static listLocal () { | 1066 | static listLocal (): Bluebird<MVideoWithAllFiles[]> { |
1043 | const query = { | 1067 | const query = { |
1044 | where: { | 1068 | where: { |
1045 | remote: false | 1069 | remote: false |
@@ -1159,7 +1183,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1159 | }) | 1183 | }) |
1160 | } | 1184 | } |
1161 | 1185 | ||
1162 | static listUserVideosForApi (accountId: number, start: number, count: number, sort: string, withFiles = false) { | 1186 | static listUserVideosForApi (accountId: number, start: number, count: number, sort: string) { |
1163 | function buildBaseQuery (): FindOptions { | 1187 | function buildBaseQuery (): FindOptions { |
1164 | return { | 1188 | return { |
1165 | offset: start, | 1189 | offset: start, |
@@ -1192,16 +1216,9 @@ export class VideoModel extends Model<VideoModel> { | |||
1192 | ScopeNames.WITH_THUMBNAILS | 1216 | ScopeNames.WITH_THUMBNAILS |
1193 | ] | 1217 | ] |
1194 | 1218 | ||
1195 | if (withFiles === true) { | ||
1196 | findQuery.include.push({ | ||
1197 | model: VideoFileModel.unscoped(), | ||
1198 | required: true | ||
1199 | }) | ||
1200 | } | ||
1201 | |||
1202 | return Promise.all([ | 1219 | return Promise.all([ |
1203 | VideoModel.count(countQuery), | 1220 | VideoModel.count(countQuery), |
1204 | VideoModel.scope(findScopes).findAll(findQuery) | 1221 | VideoModel.scope(findScopes).findAll<MVideoForUser>(findQuery) |
1205 | ]).then(([ count, rows ]) => { | 1222 | ]).then(([ count, rows ]) => { |
1206 | return { | 1223 | return { |
1207 | data: rows, | 1224 | data: rows, |
@@ -1228,8 +1245,8 @@ export class VideoModel extends Model<VideoModel> { | |||
1228 | followerActorId?: number | 1245 | followerActorId?: number |
1229 | videoPlaylistId?: number, | 1246 | videoPlaylistId?: number, |
1230 | trendingDays?: number, | 1247 | trendingDays?: number, |
1231 | user?: UserModel, | 1248 | user?: MUserAccountId, |
1232 | historyOfUser?: UserModel | 1249 | historyOfUser?: MUserId |
1233 | }, countVideos = true) { | 1250 | }, countVideos = true) { |
1234 | if (options.filter && options.filter === 'all-local' && !options.user.hasRight(UserRight.SEE_ALL_VIDEOS)) { | 1251 | 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') | 1252 | throw new Error('Try to filter all-local but no user has not the see all videos right') |
@@ -1294,7 +1311,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1294 | tagsAllOf?: string[] | 1311 | tagsAllOf?: string[] |
1295 | durationMin?: number // seconds | 1312 | durationMin?: number // seconds |
1296 | durationMax?: number // seconds | 1313 | durationMax?: number // seconds |
1297 | user?: UserModel, | 1314 | user?: MUserAccountId, |
1298 | filter?: VideoFilter | 1315 | filter?: VideoFilter |
1299 | }) { | 1316 | }) { |
1300 | const whereAnd = [] | 1317 | const whereAnd = [] |
@@ -1387,7 +1404,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1387 | return VideoModel.getAvailableForApi(query, queryOptions) | 1404 | return VideoModel.getAvailableForApi(query, queryOptions) |
1388 | } | 1405 | } |
1389 | 1406 | ||
1390 | static load (id: number | string, t?: Transaction) { | 1407 | static load (id: number | string, t?: Transaction): Bluebird<MVideoThumbnail> { |
1391 | const where = buildWhereIdOrUUID(id) | 1408 | const where = buildWhereIdOrUUID(id) |
1392 | const options = { | 1409 | const options = { |
1393 | where, | 1410 | where, |
@@ -1397,7 +1414,20 @@ export class VideoModel extends Model<VideoModel> { | |||
1397 | return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(options) | 1414 | return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(options) |
1398 | } | 1415 | } |
1399 | 1416 | ||
1400 | static loadWithRights (id: number | string, t?: Transaction) { | 1417 | static loadWithBlacklist (id: number | string, t?: Transaction): Bluebird<MVideoThumbnailBlacklist> { |
1418 | const where = buildWhereIdOrUUID(id) | ||
1419 | const options = { | ||
1420 | where, | ||
1421 | transaction: t | ||
1422 | } | ||
1423 | |||
1424 | return VideoModel.scope([ | ||
1425 | ScopeNames.WITH_THUMBNAILS, | ||
1426 | ScopeNames.WITH_BLACKLISTED | ||
1427 | ]).findOne(options) | ||
1428 | } | ||
1429 | |||
1430 | static loadWithRights (id: number | string, t?: Transaction): Bluebird<MVideoWithRights> { | ||
1401 | const where = buildWhereIdOrUUID(id) | 1431 | const where = buildWhereIdOrUUID(id) |
1402 | const options = { | 1432 | const options = { |
1403 | where, | 1433 | where, |
@@ -1411,7 +1441,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1411 | ]).findOne(options) | 1441 | ]).findOne(options) |
1412 | } | 1442 | } |
1413 | 1443 | ||
1414 | static loadOnlyId (id: number | string, t?: Transaction) { | 1444 | static loadOnlyId (id: number | string, t?: Transaction): Bluebird<MVideoIdThumbnail> { |
1415 | const where = buildWhereIdOrUUID(id) | 1445 | const where = buildWhereIdOrUUID(id) |
1416 | 1446 | ||
1417 | const options = { | 1447 | const options = { |
@@ -1423,7 +1453,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1423 | return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(options) | 1453 | return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(options) |
1424 | } | 1454 | } |
1425 | 1455 | ||
1426 | static loadWithFiles (id: number | string, t?: Transaction, logging?: boolean) { | 1456 | static loadWithFiles (id: number | string, t?: Transaction, logging?: boolean): Bluebird<MVideoWithAllFiles> { |
1427 | const where = buildWhereIdOrUUID(id) | 1457 | const where = buildWhereIdOrUUID(id) |
1428 | 1458 | ||
1429 | const query = { | 1459 | const query = { |
@@ -1439,7 +1469,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1439 | ]).findOne(query) | 1469 | ]).findOne(query) |
1440 | } | 1470 | } |
1441 | 1471 | ||
1442 | static loadByUUID (uuid: string) { | 1472 | static loadByUUID (uuid: string): Bluebird<MVideoThumbnail> { |
1443 | const options = { | 1473 | const options = { |
1444 | where: { | 1474 | where: { |
1445 | uuid | 1475 | uuid |
@@ -1449,7 +1479,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1449 | return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(options) | 1479 | return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(options) |
1450 | } | 1480 | } |
1451 | 1481 | ||
1452 | static loadByUrl (url: string, transaction?: Transaction) { | 1482 | static loadByUrl (url: string, transaction?: Transaction): Bluebird<MVideoThumbnail> { |
1453 | const query: FindOptions = { | 1483 | const query: FindOptions = { |
1454 | where: { | 1484 | where: { |
1455 | url | 1485 | url |
@@ -1460,7 +1490,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1460 | return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(query) | 1490 | return VideoModel.scope(ScopeNames.WITH_THUMBNAILS).findOne(query) |
1461 | } | 1491 | } |
1462 | 1492 | ||
1463 | static loadByUrlAndPopulateAccount (url: string, transaction?: Transaction) { | 1493 | static loadByUrlAndPopulateAccount (url: string, transaction?: Transaction): Bluebird<MVideoAccountLightBlacklistAllFiles> { |
1464 | const query: FindOptions = { | 1494 | const query: FindOptions = { |
1465 | where: { | 1495 | where: { |
1466 | url | 1496 | url |
@@ -1472,11 +1502,12 @@ export class VideoModel extends Model<VideoModel> { | |||
1472 | ScopeNames.WITH_ACCOUNT_DETAILS, | 1502 | ScopeNames.WITH_ACCOUNT_DETAILS, |
1473 | ScopeNames.WITH_FILES, | 1503 | ScopeNames.WITH_FILES, |
1474 | ScopeNames.WITH_STREAMING_PLAYLISTS, | 1504 | ScopeNames.WITH_STREAMING_PLAYLISTS, |
1475 | ScopeNames.WITH_THUMBNAILS | 1505 | ScopeNames.WITH_THUMBNAILS, |
1506 | ScopeNames.WITH_BLACKLISTED | ||
1476 | ]).findOne(query) | 1507 | ]).findOne(query) |
1477 | } | 1508 | } |
1478 | 1509 | ||
1479 | static loadAndPopulateAccountAndServerAndTags (id: number | string, t?: Transaction, userId?: number) { | 1510 | static loadAndPopulateAccountAndServerAndTags (id: number | string, t?: Transaction, userId?: number): Bluebird<MVideoFullLight> { |
1480 | const where = buildWhereIdOrUUID(id) | 1511 | const where = buildWhereIdOrUUID(id) |
1481 | 1512 | ||
1482 | const options = { | 1513 | const options = { |
@@ -1508,7 +1539,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1508 | id: number | string, | 1539 | id: number | string, |
1509 | t?: Transaction, | 1540 | t?: Transaction, |
1510 | userId?: number | 1541 | userId?: number |
1511 | }) { | 1542 | }): Bluebird<MVideoDetails> { |
1512 | const { id, t, userId } = parameters | 1543 | const { id, t, userId } = parameters |
1513 | const where = buildWhereIdOrUUID(id) | 1544 | const where = buildWhereIdOrUUID(id) |
1514 | 1545 | ||
@@ -1586,7 +1617,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1586 | .then(results => results.length === 1) | 1617 | .then(results => results.length === 1) |
1587 | } | 1618 | } |
1588 | 1619 | ||
1589 | static bulkUpdateSupportField (videoChannel: VideoChannelModel, t: Transaction) { | 1620 | static bulkUpdateSupportField (videoChannel: MChannel, t: Transaction) { |
1590 | const options = { | 1621 | const options = { |
1591 | where: { | 1622 | where: { |
1592 | channelId: videoChannel.id | 1623 | channelId: videoChannel.id |
@@ -1597,7 +1628,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1597 | return VideoModel.update({ support: videoChannel.support }, options) | 1628 | return VideoModel.update({ support: videoChannel.support }, options) |
1598 | } | 1629 | } |
1599 | 1630 | ||
1600 | static getAllIdsFromChannel (videoChannel: VideoChannelModel) { | 1631 | static getAllIdsFromChannel (videoChannel: MChannelId): Bluebird<number[]> { |
1601 | const query = { | 1632 | const query = { |
1602 | attributes: [ 'id' ], | 1633 | attributes: [ 'id' ], |
1603 | where: { | 1634 | where: { |
@@ -1756,20 +1787,20 @@ export class VideoModel extends Model<VideoModel> { | |||
1756 | this.VideoChannel.Account.isBlocked() | 1787 | this.VideoChannel.Account.isBlocked() |
1757 | } | 1788 | } |
1758 | 1789 | ||
1759 | getOriginalFile () { | 1790 | getOriginalFile <T extends MVideoWithFile> (this: T) { |
1760 | if (Array.isArray(this.VideoFiles) === false) return undefined | 1791 | if (Array.isArray(this.VideoFiles) === false) return undefined |
1761 | 1792 | ||
1762 | // The original file is the file that have the higher resolution | 1793 | // The original file is the file that have the higher resolution |
1763 | return maxBy(this.VideoFiles, file => file.resolution) | 1794 | return maxBy(this.VideoFiles, file => file.resolution) |
1764 | } | 1795 | } |
1765 | 1796 | ||
1766 | getFile (resolution: number) { | 1797 | getFile <T extends MVideoWithFile> (this: T, resolution: number) { |
1767 | if (Array.isArray(this.VideoFiles) === false) return undefined | 1798 | if (Array.isArray(this.VideoFiles) === false) return undefined |
1768 | 1799 | ||
1769 | return this.VideoFiles.find(f => f.resolution === resolution) | 1800 | return this.VideoFiles.find(f => f.resolution === resolution) |
1770 | } | 1801 | } |
1771 | 1802 | ||
1772 | async addAndSaveThumbnail (thumbnail: ThumbnailModel, transaction: Transaction) { | 1803 | async addAndSaveThumbnail (thumbnail: MThumbnail, transaction: Transaction) { |
1773 | thumbnail.videoId = this.id | 1804 | thumbnail.videoId = this.id |
1774 | 1805 | ||
1775 | const savedThumbnail = await thumbnail.save({ transaction }) | 1806 | const savedThumbnail = await thumbnail.save({ transaction }) |
@@ -1782,7 +1813,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1782 | this.Thumbnails.push(savedThumbnail) | 1813 | this.Thumbnails.push(savedThumbnail) |
1783 | } | 1814 | } |
1784 | 1815 | ||
1785 | getVideoFilename (videoFile: VideoFileModel) { | 1816 | getVideoFilename (videoFile: MVideoFile) { |
1786 | return this.uuid + '-' + videoFile.resolution + videoFile.extname | 1817 | return this.uuid + '-' + videoFile.resolution + videoFile.extname |
1787 | } | 1818 | } |
1788 | 1819 | ||
@@ -1806,7 +1837,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1806 | return this.Thumbnails.find(t => t.type === ThumbnailType.PREVIEW) | 1837 | return this.Thumbnails.find(t => t.type === ThumbnailType.PREVIEW) |
1807 | } | 1838 | } |
1808 | 1839 | ||
1809 | getTorrentFileName (videoFile: VideoFileModel) { | 1840 | getTorrentFileName (videoFile: MVideoFile) { |
1810 | const extension = '.torrent' | 1841 | const extension = '.torrent' |
1811 | return this.uuid + '-' + videoFile.resolution + extension | 1842 | return this.uuid + '-' + videoFile.resolution + extension |
1812 | } | 1843 | } |
@@ -1815,15 +1846,15 @@ export class VideoModel extends Model<VideoModel> { | |||
1815 | return this.remote === false | 1846 | return this.remote === false |
1816 | } | 1847 | } |
1817 | 1848 | ||
1818 | getTorrentFilePath (videoFile: VideoFileModel) { | 1849 | getTorrentFilePath (videoFile: MVideoFile) { |
1819 | return join(CONFIG.STORAGE.TORRENTS_DIR, this.getTorrentFileName(videoFile)) | 1850 | return join(CONFIG.STORAGE.TORRENTS_DIR, this.getTorrentFileName(videoFile)) |
1820 | } | 1851 | } |
1821 | 1852 | ||
1822 | getVideoFilePath (videoFile: VideoFileModel) { | 1853 | getVideoFilePath (videoFile: MVideoFile) { |
1823 | return join(CONFIG.STORAGE.VIDEOS_DIR, this.getVideoFilename(videoFile)) | 1854 | return join(CONFIG.STORAGE.VIDEOS_DIR, this.getVideoFilename(videoFile)) |
1824 | } | 1855 | } |
1825 | 1856 | ||
1826 | async createTorrentAndSetInfoHash (videoFile: VideoFileModel) { | 1857 | async createTorrentAndSetInfoHash (videoFile: MVideoFile) { |
1827 | const options = { | 1858 | const options = { |
1828 | // Keep the extname, it's used by the client to stream the file inside a web browser | 1859 | // 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}`, | 1860 | name: `${this.name} ${videoFile.resolution}p${videoFile.extname}`, |
@@ -1869,11 +1900,11 @@ export class VideoModel extends Model<VideoModel> { | |||
1869 | return join(LAZY_STATIC_PATHS.PREVIEWS, preview.filename) | 1900 | return join(LAZY_STATIC_PATHS.PREVIEWS, preview.filename) |
1870 | } | 1901 | } |
1871 | 1902 | ||
1872 | toFormattedJSON (options?: VideoFormattingJSONOptions): Video { | 1903 | toFormattedJSON (this: MVideoFormattable, options?: VideoFormattingJSONOptions): Video { |
1873 | return videoModelToFormattedJSON(this, options) | 1904 | return videoModelToFormattedJSON(this, options) |
1874 | } | 1905 | } |
1875 | 1906 | ||
1876 | toFormattedDetailsJSON (): VideoDetails { | 1907 | toFormattedDetailsJSON (this: MVideoFormattableDetails): VideoDetails { |
1877 | return videoModelToFormattedDetailsJSON(this) | 1908 | return videoModelToFormattedDetailsJSON(this) |
1878 | } | 1909 | } |
1879 | 1910 | ||
@@ -1881,7 +1912,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1881 | return videoFilesModelToFormattedJSON(this, this.VideoFiles) | 1912 | return videoFilesModelToFormattedJSON(this, this.VideoFiles) |
1882 | } | 1913 | } |
1883 | 1914 | ||
1884 | toActivityPubObject (): VideoTorrentObject { | 1915 | toActivityPubObject (this: MVideoAP): VideoTorrentObject { |
1885 | return videoModelToActivityPubObject(this) | 1916 | return videoModelToActivityPubObject(this) |
1886 | } | 1917 | } |
1887 | 1918 | ||
@@ -1908,7 +1939,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1908 | return this.VideoStreamingPlaylists.find(p => p.type === VideoStreamingPlaylistType.HLS) | 1939 | return this.VideoStreamingPlaylists.find(p => p.type === VideoStreamingPlaylistType.HLS) |
1909 | } | 1940 | } |
1910 | 1941 | ||
1911 | removeFile (videoFile: VideoFileModel, isRedundancy = false) { | 1942 | removeFile (videoFile: MVideoFile, isRedundancy = false) { |
1912 | const baseDir = isRedundancy ? CONFIG.STORAGE.REDUNDANCY_DIR : CONFIG.STORAGE.VIDEOS_DIR | 1943 | const baseDir = isRedundancy ? CONFIG.STORAGE.REDUNDANCY_DIR : CONFIG.STORAGE.VIDEOS_DIR |
1913 | 1944 | ||
1914 | const filePath = join(baseDir, this.getVideoFilename(videoFile)) | 1945 | const filePath = join(baseDir, this.getVideoFilename(videoFile)) |
@@ -1916,7 +1947,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1916 | .catch(err => logger.warn('Cannot delete file %s.', filePath, { err })) | 1947 | .catch(err => logger.warn('Cannot delete file %s.', filePath, { err })) |
1917 | } | 1948 | } |
1918 | 1949 | ||
1919 | removeTorrent (videoFile: VideoFileModel) { | 1950 | removeTorrent (videoFile: MVideoFile) { |
1920 | const torrentPath = join(CONFIG.STORAGE.TORRENTS_DIR, this.getTorrentFileName(videoFile)) | 1951 | const torrentPath = join(CONFIG.STORAGE.TORRENTS_DIR, this.getTorrentFileName(videoFile)) |
1921 | return remove(torrentPath) | 1952 | return remove(torrentPath) |
1922 | .catch(err => logger.warn('Cannot delete torrent %s.', torrentPath, { err })) | 1953 | .catch(err => logger.warn('Cannot delete torrent %s.', torrentPath, { err })) |
@@ -1957,7 +1988,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1957 | return { baseUrlHttp, baseUrlWs } | 1988 | return { baseUrlHttp, baseUrlWs } |
1958 | } | 1989 | } |
1959 | 1990 | ||
1960 | generateMagnetUri (videoFile: VideoFileModel, baseUrlHttp: string, baseUrlWs: string) { | 1991 | generateMagnetUri (videoFile: MVideoFileRedundanciesOpt, baseUrlHttp: string, baseUrlWs: string) { |
1961 | const xs = this.getTorrentUrl(videoFile, baseUrlHttp) | 1992 | const xs = this.getTorrentUrl(videoFile, baseUrlHttp) |
1962 | const announce = this.getTrackerUrls(baseUrlHttp, baseUrlWs) | 1993 | const announce = this.getTrackerUrls(baseUrlHttp, baseUrlWs) |
1963 | let urlList = [ this.getVideoFileUrl(videoFile, baseUrlHttp) ] | 1994 | let urlList = [ this.getVideoFileUrl(videoFile, baseUrlHttp) ] |
@@ -1980,27 +2011,27 @@ export class VideoModel extends Model<VideoModel> { | |||
1980 | return [ baseUrlWs + '/tracker/socket', baseUrlHttp + '/tracker/announce' ] | 2011 | return [ baseUrlWs + '/tracker/socket', baseUrlHttp + '/tracker/announce' ] |
1981 | } | 2012 | } |
1982 | 2013 | ||
1983 | getTorrentUrl (videoFile: VideoFileModel, baseUrlHttp: string) { | 2014 | getTorrentUrl (videoFile: MVideoFile, baseUrlHttp: string) { |
1984 | return baseUrlHttp + STATIC_PATHS.TORRENTS + this.getTorrentFileName(videoFile) | 2015 | return baseUrlHttp + STATIC_PATHS.TORRENTS + this.getTorrentFileName(videoFile) |
1985 | } | 2016 | } |
1986 | 2017 | ||
1987 | getTorrentDownloadUrl (videoFile: VideoFileModel, baseUrlHttp: string) { | 2018 | getTorrentDownloadUrl (videoFile: MVideoFile, baseUrlHttp: string) { |
1988 | return baseUrlHttp + STATIC_DOWNLOAD_PATHS.TORRENTS + this.getTorrentFileName(videoFile) | 2019 | return baseUrlHttp + STATIC_DOWNLOAD_PATHS.TORRENTS + this.getTorrentFileName(videoFile) |
1989 | } | 2020 | } |
1990 | 2021 | ||
1991 | getVideoFileUrl (videoFile: VideoFileModel, baseUrlHttp: string) { | 2022 | getVideoFileUrl (videoFile: MVideoFile, baseUrlHttp: string) { |
1992 | return baseUrlHttp + STATIC_PATHS.WEBSEED + this.getVideoFilename(videoFile) | 2023 | return baseUrlHttp + STATIC_PATHS.WEBSEED + this.getVideoFilename(videoFile) |
1993 | } | 2024 | } |
1994 | 2025 | ||
1995 | getVideoRedundancyUrl (videoFile: VideoFileModel, baseUrlHttp: string) { | 2026 | getVideoRedundancyUrl (videoFile: MVideoFile, baseUrlHttp: string) { |
1996 | return baseUrlHttp + STATIC_PATHS.REDUNDANCY + this.getVideoFilename(videoFile) | 2027 | return baseUrlHttp + STATIC_PATHS.REDUNDANCY + this.getVideoFilename(videoFile) |
1997 | } | 2028 | } |
1998 | 2029 | ||
1999 | getVideoFileDownloadUrl (videoFile: VideoFileModel, baseUrlHttp: string) { | 2030 | getVideoFileDownloadUrl (videoFile: MVideoFile, baseUrlHttp: string) { |
2000 | return baseUrlHttp + STATIC_DOWNLOAD_PATHS.VIDEOS + this.getVideoFilename(videoFile) | 2031 | return baseUrlHttp + STATIC_DOWNLOAD_PATHS.VIDEOS + this.getVideoFilename(videoFile) |
2001 | } | 2032 | } |
2002 | 2033 | ||
2003 | getBandwidthBits (videoFile: VideoFileModel) { | 2034 | getBandwidthBits (videoFile: MVideoFile) { |
2004 | return Math.ceil((videoFile.size * 8) / this.duration) | 2035 | return Math.ceil((videoFile.size * 8) / this.duration) |
2005 | } | 2036 | } |
2006 | } | 2037 | } |