Handle higher FPS for high resolution (test)
[oweals/peertube.git] / server / helpers / custom-validators / videos.ts
1 import { Response } from 'express'
2 import 'express-validator'
3 import { values } from 'lodash'
4 import 'multer'
5 import * as validator from 'validator'
6 import { UserRight, VideoPrivacy, VideoRateType } from '../../../shared'
7 import {
8   CONSTRAINTS_FIELDS,
9   VIDEO_CATEGORIES,
10   VIDEO_LICENCES,
11   VIDEO_MIMETYPE_EXT,
12   VIDEO_PRIVACIES,
13   VIDEO_RATE_TYPES,
14   VIDEO_STATES
15 } from '../../initializers'
16 import { VideoModel } from '../../models/video/video'
17 import { exists, isArray, isFileValid } from './misc'
18 import { VideoChannelModel } from '../../models/video/video-channel'
19 import { UserModel } from '../../models/account/user'
20
21 const VIDEOS_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEOS
22 const VIDEO_ABUSES_CONSTRAINTS_FIELDS = CONSTRAINTS_FIELDS.VIDEO_ABUSES
23
24 function isVideoCategoryValid (value: any) {
25   return value === null || VIDEO_CATEGORIES[ value ] !== undefined
26 }
27
28 function isVideoStateValid (value: any) {
29   return exists(value) && VIDEO_STATES[ value ] !== undefined
30 }
31
32 function isVideoLicenceValid (value: any) {
33   return value === null || VIDEO_LICENCES[ value ] !== undefined
34 }
35
36 function isVideoLanguageValid (value: any) {
37   return value === null ||
38     (typeof value === 'string' && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.LANGUAGE))
39 }
40
41 function isVideoDurationValid (value: string) {
42   return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.DURATION)
43 }
44
45 function isVideoTruncatedDescriptionValid (value: string) {
46   return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.TRUNCATED_DESCRIPTION)
47 }
48
49 function isVideoDescriptionValid (value: string) {
50   return value === null || (exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.DESCRIPTION))
51 }
52
53 function isVideoSupportValid (value: string) {
54   return value === null || (exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.SUPPORT))
55 }
56
57 function isVideoNameValid (value: string) {
58   return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.NAME)
59 }
60
61 function isVideoTagValid (tag: string) {
62   return exists(tag) && validator.isLength(tag, VIDEOS_CONSTRAINTS_FIELDS.TAG)
63 }
64
65 function isVideoTagsValid (tags: string[]) {
66   return tags === null || (
67     isArray(tags) &&
68     validator.isInt(tags.length.toString(), VIDEOS_CONSTRAINTS_FIELDS.TAGS) &&
69     tags.every(tag => isVideoTagValid(tag))
70   )
71 }
72
73 function isVideoAbuseReasonValid (value: string) {
74   return exists(value) && validator.isLength(value, VIDEO_ABUSES_CONSTRAINTS_FIELDS.REASON)
75 }
76
77 function isVideoViewsValid (value: string) {
78   return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.VIEWS)
79 }
80
81 function isVideoRatingTypeValid (value: string) {
82   return value === 'none' || values(VIDEO_RATE_TYPES).indexOf(value as VideoRateType) !== -1
83 }
84
85 const videoFileTypes = Object.keys(VIDEO_MIMETYPE_EXT).map(m => `(${m})`)
86 const videoFileTypesRegex = videoFileTypes.join('|')
87
88 function isVideoFile (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[]) {
89   return isFileValid(files, videoFileTypesRegex, 'videofile', null)
90 }
91
92 const videoImageTypes = CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME
93                                           .map(v => v.replace('.', ''))
94                                           .join('|')
95 const videoImageTypesRegex = `image/(${videoImageTypes})`
96
97 function isVideoImage (files: { [ fieldname: string ]: Express.Multer.File[] } | Express.Multer.File[], field: string) {
98   return isFileValid(files, videoImageTypesRegex, field, CONSTRAINTS_FIELDS.VIDEOS.IMAGE.FILE_SIZE.max, true)
99 }
100
101 function isVideoPrivacyValid (value: number) {
102   return validator.isInt(value + '') && VIDEO_PRIVACIES[ value ] !== undefined
103 }
104
105 function isScheduleVideoUpdatePrivacyValid (value: number) {
106   return validator.isInt(value + '') &&
107     (
108       value === VideoPrivacy.UNLISTED ||
109       value === VideoPrivacy.PUBLIC
110     )
111 }
112
113 function isVideoFileInfoHashValid (value: string) {
114   return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.INFO_HASH)
115 }
116
117 function isVideoFileResolutionValid (value: string) {
118   return exists(value) && validator.isInt(value + '')
119 }
120
121 function isVideoFPSResolutionValid (value: string) {
122   return value === null || validator.isInt(value + '')
123 }
124
125 function isVideoFileSizeValid (value: string) {
126   return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.FILE_SIZE)
127 }
128
129 async function isVideoExist (id: string, res: Response) {
130   let video: VideoModel
131
132   if (validator.isInt(id)) {
133     video = await VideoModel.loadAndPopulateAccountAndServerAndTags(+id)
134   } else { // UUID
135     video = await VideoModel.loadByUUIDAndPopulateAccountAndServerAndTags(id)
136   }
137
138   if (!video) {
139     res.status(404)
140        .json({ error: 'Video not found' })
141        .end()
142
143     return false
144   }
145
146   res.locals.video = video
147   return true
148 }
149
150 async function isVideoChannelOfAccountExist (channelId: number, user: UserModel, res: Response) {
151   if (user.hasRight(UserRight.UPDATE_ANY_VIDEO) === true) {
152     const videoChannel = await VideoChannelModel.loadAndPopulateAccount(channelId)
153     if (!videoChannel) {
154       res.status(400)
155          .json({ error: 'Unknown video video channel on this instance.' })
156          .end()
157
158       return false
159     }
160
161     res.locals.videoChannel = videoChannel
162     return true
163   }
164
165   const videoChannel = await VideoChannelModel.loadByIdAndAccount(channelId, user.Account.id)
166   if (!videoChannel) {
167     res.status(400)
168        .json({ error: 'Unknown video video channel for this account.' })
169        .end()
170
171     return false
172   }
173
174   res.locals.videoChannel = videoChannel
175   return true
176 }
177
178 // ---------------------------------------------------------------------------
179
180 export {
181   isVideoCategoryValid,
182   isVideoLicenceValid,
183   isVideoLanguageValid,
184   isVideoTruncatedDescriptionValid,
185   isVideoDescriptionValid,
186   isVideoFileInfoHashValid,
187   isVideoNameValid,
188   isVideoTagsValid,
189   isVideoFPSResolutionValid,
190   isScheduleVideoUpdatePrivacyValid,
191   isVideoAbuseReasonValid,
192   isVideoFile,
193   isVideoStateValid,
194   isVideoViewsValid,
195   isVideoRatingTypeValid,
196   isVideoDurationValid,
197   isVideoTagValid,
198   isVideoPrivacyValid,
199   isVideoFileResolutionValid,
200   isVideoFileSizeValid,
201   isVideoExist,
202   isVideoImage,
203   isVideoChannelOfAccountExist,
204   isVideoSupportValid
205 }