aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/models/video/video.ts
diff options
context:
space:
mode:
Diffstat (limited to 'server/models/video/video.ts')
-rw-r--r--server/models/video/video.ts127
1 files changed, 62 insertions, 65 deletions
diff --git a/server/models/video/video.ts b/server/models/video/video.ts
index 4516b9c7b..7a102b058 100644
--- a/server/models/video/video.ts
+++ b/server/models/video/video.ts
@@ -40,7 +40,7 @@ import {
40 isVideoDurationValid, 40 isVideoDurationValid,
41 isVideoLanguageValid, 41 isVideoLanguageValid,
42 isVideoLicenceValid, 42 isVideoLicenceValid,
43 isVideoNameValid, isVideoOriginallyPublishedAtValid, 43 isVideoNameValid,
44 isVideoPrivacyValid, 44 isVideoPrivacyValid,
45 isVideoStateValid, 45 isVideoStateValid,
46 isVideoSupportValid 46 isVideoSupportValid
@@ -52,7 +52,9 @@ import {
52 ACTIVITY_PUB, 52 ACTIVITY_PUB,
53 API_VERSION, 53 API_VERSION,
54 CONFIG, 54 CONFIG,
55 CONSTRAINTS_FIELDS, HLS_PLAYLIST_DIRECTORY, HLS_REDUNDANCY_DIRECTORY, 55 CONSTRAINTS_FIELDS,
56 HLS_PLAYLIST_DIRECTORY,
57 HLS_REDUNDANCY_DIRECTORY,
56 PREVIEWS_SIZE, 58 PREVIEWS_SIZE,
57 REMOTE_SCHEME, 59 REMOTE_SCHEME,
58 STATIC_DOWNLOAD_PATHS, 60 STATIC_DOWNLOAD_PATHS,
@@ -70,10 +72,17 @@ import { AccountVideoRateModel } from '../account/account-video-rate'
70import { ActorModel } from '../activitypub/actor' 72import { ActorModel } from '../activitypub/actor'
71import { AvatarModel } from '../avatar/avatar' 73import { AvatarModel } from '../avatar/avatar'
72import { ServerModel } from '../server/server' 74import { ServerModel } from '../server/server'
73import { buildBlockedAccountSQL, buildTrigramSearchIndex, createSimilarityAttribute, getVideoSort, throwIfNotValid } from '../utils' 75import {
76 buildBlockedAccountSQL,
77 buildTrigramSearchIndex,
78 buildWhereIdOrUUID,
79 createSimilarityAttribute,
80 getVideoSort,
81 throwIfNotValid
82} from '../utils'
74import { TagModel } from './tag' 83import { TagModel } from './tag'
75import { VideoAbuseModel } from './video-abuse' 84import { VideoAbuseModel } from './video-abuse'
76import { VideoChannelModel } from './video-channel' 85import { VideoChannelModel, ScopeNames as VideoChannelScopeNames } from './video-channel'
77import { VideoCommentModel } from './video-comment' 86import { VideoCommentModel } from './video-comment'
78import { VideoFileModel } from './video-file' 87import { VideoFileModel } from './video-file'
79import { VideoShareModel } from './video-share' 88import { VideoShareModel } from './video-share'
@@ -91,11 +100,11 @@ import {
91 videoModelToFormattedDetailsJSON, 100 videoModelToFormattedDetailsJSON,
92 videoModelToFormattedJSON 101 videoModelToFormattedJSON
93} from './video-format-utils' 102} from './video-format-utils'
94import * as validator from 'validator'
95import { UserVideoHistoryModel } from '../account/user-video-history' 103import { UserVideoHistoryModel } from '../account/user-video-history'
96import { UserModel } from '../account/user' 104import { UserModel } from '../account/user'
97import { VideoImportModel } from './video-import' 105import { VideoImportModel } from './video-import'
98import { VideoStreamingPlaylistModel } from './video-streaming-playlist' 106import { VideoStreamingPlaylistModel } from './video-streaming-playlist'
107import { VideoPlaylistElementModel } from './video-playlist-element'
99 108
100// FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation 109// FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation
101const indexes: Sequelize.DefineIndexesOptions[] = [ 110const indexes: Sequelize.DefineIndexesOptions[] = [
@@ -175,6 +184,9 @@ export enum ScopeNames {
175 184
176type ForAPIOptions = { 185type ForAPIOptions = {
177 ids: number[] 186 ids: number[]
187
188 videoPlaylistId?: number
189
178 withFiles?: boolean 190 withFiles?: boolean
179} 191}
180 192
@@ -182,6 +194,7 @@ type AvailableForListIDsOptions = {
182 serverAccountId: number 194 serverAccountId: number
183 followerActorId: number 195 followerActorId: number
184 includeLocalVideos: boolean 196 includeLocalVideos: boolean
197
185 filter?: VideoFilter 198 filter?: VideoFilter
186 categoryOneOf?: number[] 199 categoryOneOf?: number[]
187 nsfw?: boolean 200 nsfw?: boolean
@@ -189,9 +202,14 @@ type AvailableForListIDsOptions = {
189 languageOneOf?: string[] 202 languageOneOf?: string[]
190 tagsOneOf?: string[] 203 tagsOneOf?: string[]
191 tagsAllOf?: string[] 204 tagsAllOf?: string[]
205
192 withFiles?: boolean 206 withFiles?: boolean
207
193 accountId?: number 208 accountId?: number
194 videoChannelId?: number 209 videoChannelId?: number
210
211 videoPlaylistId?: number
212
195 trendingDays?: number 213 trendingDays?: number
196 user?: UserModel, 214 user?: UserModel,
197 historyOfUser?: UserModel 215 historyOfUser?: UserModel
@@ -199,62 +217,17 @@ type AvailableForListIDsOptions = {
199 217
200@Scopes({ 218@Scopes({
201 [ ScopeNames.FOR_API ]: (options: ForAPIOptions) => { 219 [ ScopeNames.FOR_API ]: (options: ForAPIOptions) => {
202 const accountInclude = {
203 attributes: [ 'id', 'name' ],
204 model: AccountModel.unscoped(),
205 required: true,
206 include: [
207 {
208 attributes: [ 'id', 'uuid', 'preferredUsername', 'url', 'serverId', 'avatarId' ],
209 model: ActorModel.unscoped(),
210 required: true,
211 include: [
212 {
213 attributes: [ 'host' ],
214 model: ServerModel.unscoped(),
215 required: false
216 },
217 {
218 model: AvatarModel.unscoped(),
219 required: false
220 }
221 ]
222 }
223 ]
224 }
225
226 const videoChannelInclude = {
227 attributes: [ 'name', 'description', 'id' ],
228 model: VideoChannelModel.unscoped(),
229 required: true,
230 include: [
231 {
232 attributes: [ 'uuid', 'preferredUsername', 'url', 'serverId', 'avatarId' ],
233 model: ActorModel.unscoped(),
234 required: true,
235 include: [
236 {
237 attributes: [ 'host' ],
238 model: ServerModel.unscoped(),
239 required: false
240 },
241 {
242 model: AvatarModel.unscoped(),
243 required: false
244 }
245 ]
246 },
247 accountInclude
248 ]
249 }
250
251 const query: IFindOptions<VideoModel> = { 220 const query: IFindOptions<VideoModel> = {
252 where: { 221 where: {
253 id: { 222 id: {
254 [ Sequelize.Op.any ]: options.ids 223 [ Sequelize.Op.any ]: options.ids
255 } 224 }
256 }, 225 },
257 include: [ videoChannelInclude ] 226 include: [
227 {
228 model: VideoChannelModel.scope(VideoChannelScopeNames.SUMMARY)
229 }
230 ]
258 } 231 }
259 232
260 if (options.withFiles === true) { 233 if (options.withFiles === true) {
@@ -264,6 +237,13 @@ type AvailableForListIDsOptions = {
264 }) 237 })
265 } 238 }
266 239
240 if (options.videoPlaylistId) {
241 query.include.push({
242 model: VideoPlaylistElementModel.unscoped(),
243 required: true
244 })
245 }
246
267 return query 247 return query
268 }, 248 },
269 [ ScopeNames.AVAILABLE_FOR_LIST_IDS ]: (options: AvailableForListIDsOptions) => { 249 [ ScopeNames.AVAILABLE_FOR_LIST_IDS ]: (options: AvailableForListIDsOptions) => {
@@ -315,6 +295,17 @@ type AvailableForListIDsOptions = {
315 Object.assign(query.where, privacyWhere) 295 Object.assign(query.where, privacyWhere)
316 } 296 }
317 297
298 if (options.videoPlaylistId) {
299 query.include.push({
300 attributes: [],
301 model: VideoPlaylistElementModel.unscoped(),
302 required: true,
303 where: {
304 videoPlaylistId: options.videoPlaylistId
305 }
306 })
307 }
308
318 if (options.filter || options.accountId || options.videoChannelId) { 309 if (options.filter || options.accountId || options.videoChannelId) {
319 const videoChannelInclude: IIncludeOptions = { 310 const videoChannelInclude: IIncludeOptions = {
320 attributes: [], 311 attributes: [],
@@ -772,6 +763,15 @@ export class VideoModel extends Model<VideoModel> {
772 }) 763 })
773 Tags: TagModel[] 764 Tags: TagModel[]
774 765
766 @HasMany(() => VideoPlaylistElementModel, {
767 foreignKey: {
768 name: 'videoId',
769 allowNull: false
770 },
771 onDelete: 'cascade'
772 })
773 VideoPlaylistElements: VideoPlaylistElementModel[]
774
775 @HasMany(() => VideoAbuseModel, { 775 @HasMany(() => VideoAbuseModel, {
776 foreignKey: { 776 foreignKey: {
777 name: 'videoId', 777 name: 'videoId',
@@ -1118,6 +1118,7 @@ export class VideoModel extends Model<VideoModel> {
1118 accountId?: number, 1118 accountId?: number,
1119 videoChannelId?: number, 1119 videoChannelId?: number,
1120 followerActorId?: number 1120 followerActorId?: number
1121 videoPlaylistId?: number,
1121 trendingDays?: number, 1122 trendingDays?: number,
1122 user?: UserModel, 1123 user?: UserModel,
1123 historyOfUser?: UserModel 1124 historyOfUser?: UserModel
@@ -1157,6 +1158,7 @@ export class VideoModel extends Model<VideoModel> {
1157 withFiles: options.withFiles, 1158 withFiles: options.withFiles,
1158 accountId: options.accountId, 1159 accountId: options.accountId,
1159 videoChannelId: options.videoChannelId, 1160 videoChannelId: options.videoChannelId,
1161 videoPlaylistId: options.videoPlaylistId,
1160 includeLocalVideos: options.includeLocalVideos, 1162 includeLocalVideos: options.includeLocalVideos,
1161 user: options.user, 1163 user: options.user,
1162 historyOfUser: options.historyOfUser, 1164 historyOfUser: options.historyOfUser,
@@ -1280,7 +1282,7 @@ export class VideoModel extends Model<VideoModel> {
1280 } 1282 }
1281 1283
1282 static load (id: number | string, t?: Sequelize.Transaction) { 1284 static load (id: number | string, t?: Sequelize.Transaction) {
1283 const where = VideoModel.buildWhereIdOrUUID(id) 1285 const where = buildWhereIdOrUUID(id)
1284 const options = { 1286 const options = {
1285 where, 1287 where,
1286 transaction: t 1288 transaction: t
@@ -1290,7 +1292,7 @@ export class VideoModel extends Model<VideoModel> {
1290 } 1292 }
1291 1293
1292 static loadWithRights (id: number | string, t?: Sequelize.Transaction) { 1294 static loadWithRights (id: number | string, t?: Sequelize.Transaction) {
1293 const where = VideoModel.buildWhereIdOrUUID(id) 1295 const where = buildWhereIdOrUUID(id)
1294 const options = { 1296 const options = {
1295 where, 1297 where,
1296 transaction: t 1298 transaction: t
@@ -1300,7 +1302,7 @@ export class VideoModel extends Model<VideoModel> {
1300 } 1302 }
1301 1303
1302 static loadOnlyId (id: number | string, t?: Sequelize.Transaction) { 1304 static loadOnlyId (id: number | string, t?: Sequelize.Transaction) {
1303 const where = VideoModel.buildWhereIdOrUUID(id) 1305 const where = buildWhereIdOrUUID(id)
1304 1306
1305 const options = { 1307 const options = {
1306 attributes: [ 'id' ], 1308 attributes: [ 'id' ],
@@ -1353,7 +1355,7 @@ export class VideoModel extends Model<VideoModel> {
1353 } 1355 }
1354 1356
1355 static loadAndPopulateAccountAndServerAndTags (id: number | string, t?: Sequelize.Transaction, userId?: number) { 1357 static loadAndPopulateAccountAndServerAndTags (id: number | string, t?: Sequelize.Transaction, userId?: number) {
1356 const where = VideoModel.buildWhereIdOrUUID(id) 1358 const where = buildWhereIdOrUUID(id)
1357 1359
1358 const options = { 1360 const options = {
1359 order: [ [ 'Tags', 'name', 'ASC' ] ], 1361 order: [ [ 'Tags', 'name', 'ASC' ] ],
@@ -1380,7 +1382,7 @@ export class VideoModel extends Model<VideoModel> {
1380 } 1382 }
1381 1383
1382 static loadForGetAPI (id: number | string, t?: Sequelize.Transaction, userId?: number) { 1384 static loadForGetAPI (id: number | string, t?: Sequelize.Transaction, userId?: number) {
1383 const where = VideoModel.buildWhereIdOrUUID(id) 1385 const where = buildWhereIdOrUUID(id)
1384 1386
1385 const options = { 1387 const options = {
1386 order: [ [ 'Tags', 'name', 'ASC' ] ], 1388 order: [ [ 'Tags', 'name', 'ASC' ] ],
@@ -1582,10 +1584,6 @@ export class VideoModel extends Model<VideoModel> {
1582 return VIDEO_STATES[ id ] || 'Unknown' 1584 return VIDEO_STATES[ id ] || 'Unknown'
1583 } 1585 }
1584 1586
1585 static buildWhereIdOrUUID (id: number | string) {
1586 return validator.isInt('' + id) ? { id } : { uuid: id }
1587 }
1588
1589 getOriginalFile () { 1587 getOriginalFile () {
1590 if (Array.isArray(this.VideoFiles) === false) return undefined 1588 if (Array.isArray(this.VideoFiles) === false) return undefined
1591 1589
@@ -1598,7 +1596,6 @@ export class VideoModel extends Model<VideoModel> {
1598 } 1596 }
1599 1597
1600 getThumbnailName () { 1598 getThumbnailName () {
1601 // We always have a copy of the thumbnail
1602 const extension = '.jpg' 1599 const extension = '.jpg'
1603 return this.uuid + extension 1600 return this.uuid + extension
1604 } 1601 }