diff options
Diffstat (limited to 'server/controllers/api/videos')
-rw-r--r-- | server/controllers/api/videos/index.ts | 139 |
1 files changed, 69 insertions, 70 deletions
diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts index e2798830e..63de662a7 100644 --- a/server/controllers/api/videos/index.ts +++ b/server/controllers/api/videos/index.ts | |||
@@ -15,6 +15,7 @@ import { getServerAccount } from '../../../helpers/utils' | |||
15 | import { CONFIG, VIDEO_CATEGORIES, VIDEO_LANGUAGES, VIDEO_LICENCES, VIDEO_MIMETYPE_EXT, VIDEO_PRIVACIES } from '../../../initializers' | 15 | import { CONFIG, VIDEO_CATEGORIES, VIDEO_LANGUAGES, VIDEO_LICENCES, VIDEO_MIMETYPE_EXT, VIDEO_PRIVACIES } from '../../../initializers' |
16 | import { database as db } from '../../../initializers/database' | 16 | import { database as db } from '../../../initializers/database' |
17 | import { sendAddVideo } from '../../../lib/activitypub/send/send-add' | 17 | import { sendAddVideo } from '../../../lib/activitypub/send/send-add' |
18 | import { sendCreateViewToOrigin } from '../../../lib/activitypub/send/send-create' | ||
18 | import { sendUpdateVideo } from '../../../lib/activitypub/send/send-update' | 19 | import { sendUpdateVideo } from '../../../lib/activitypub/send/send-update' |
19 | import { shareVideoByServer } from '../../../lib/activitypub/share' | 20 | import { shareVideoByServer } from '../../../lib/activitypub/share' |
20 | import { getVideoActivityPubUrl } from '../../../lib/activitypub/url' | 21 | import { getVideoActivityPubUrl } from '../../../lib/activitypub/url' |
@@ -26,7 +27,6 @@ import { | |||
26 | authenticate, | 27 | authenticate, |
27 | paginationValidator, | 28 | paginationValidator, |
28 | setPagination, | 29 | setPagination, |
29 | setVideosSearch, | ||
30 | setVideosSort, | 30 | setVideosSort, |
31 | videosAddValidator, | 31 | videosAddValidator, |
32 | videosGetValidator, | 32 | videosGetValidator, |
@@ -40,7 +40,6 @@ import { abuseVideoRouter } from './abuse' | |||
40 | import { blacklistRouter } from './blacklist' | 40 | import { blacklistRouter } from './blacklist' |
41 | import { videoChannelRouter } from './channel' | 41 | import { videoChannelRouter } from './channel' |
42 | import { rateVideoRouter } from './rate' | 42 | import { rateVideoRouter } from './rate' |
43 | import { sendCreateViewToOrigin } from '../../../lib/activitypub/send/send-create' | ||
44 | 43 | ||
45 | const videosRouter = express.Router() | 44 | const videosRouter = express.Router() |
46 | 45 | ||
@@ -84,6 +83,14 @@ videosRouter.get('/', | |||
84 | setPagination, | 83 | setPagination, |
85 | asyncMiddleware(listVideos) | 84 | asyncMiddleware(listVideos) |
86 | ) | 85 | ) |
86 | videosRouter.get('/search', | ||
87 | videosSearchValidator, | ||
88 | paginationValidator, | ||
89 | videosSortValidator, | ||
90 | setVideosSort, | ||
91 | setPagination, | ||
92 | asyncMiddleware(searchVideos) | ||
93 | ) | ||
87 | videosRouter.put('/:id', | 94 | videosRouter.put('/:id', |
88 | authenticate, | 95 | authenticate, |
89 | asyncMiddleware(videosUpdateValidator), | 96 | asyncMiddleware(videosUpdateValidator), |
@@ -115,16 +122,6 @@ videosRouter.delete('/:id', | |||
115 | asyncMiddleware(removeVideoRetryWrapper) | 122 | asyncMiddleware(removeVideoRetryWrapper) |
116 | ) | 123 | ) |
117 | 124 | ||
118 | videosRouter.get('/search/:value', | ||
119 | videosSearchValidator, | ||
120 | paginationValidator, | ||
121 | videosSortValidator, | ||
122 | setVideosSort, | ||
123 | setPagination, | ||
124 | setVideosSearch, | ||
125 | asyncMiddleware(searchVideos) | ||
126 | ) | ||
127 | |||
128 | // --------------------------------------------------------------------------- | 125 | // --------------------------------------------------------------------------- |
129 | 126 | ||
130 | export { | 127 | export { |
@@ -157,59 +154,64 @@ async function addVideoRetryWrapper (req: express.Request, res: express.Response | |||
157 | errorMessage: 'Cannot insert the video with many retries.' | 154 | errorMessage: 'Cannot insert the video with many retries.' |
158 | } | 155 | } |
159 | 156 | ||
160 | await retryTransactionWrapper(addVideo, options) | 157 | const video = await retryTransactionWrapper(addVideo, options) |
161 | 158 | ||
162 | // TODO : include Location of the new video -> 201 | 159 | res.json({ |
163 | res.type('json').status(204).end() | 160 | video: { |
161 | id: video.id, | ||
162 | uuid: video.uuid | ||
163 | } | ||
164 | }).end() | ||
164 | } | 165 | } |
165 | 166 | ||
166 | async function addVideo (req: express.Request, res: express.Response, videoPhysicalFile: Express.Multer.File) { | 167 | async function addVideo (req: express.Request, res: express.Response, videoPhysicalFile: Express.Multer.File) { |
167 | const videoInfo: VideoCreate = req.body | 168 | const videoInfo: VideoCreate = req.body |
168 | let videoUUID = '' | ||
169 | 169 | ||
170 | await db.sequelize.transaction(async t => { | 170 | // Prepare data so we don't block the transaction |
171 | const sequelizeOptions = { transaction: t } | 171 | const videoData = { |
172 | name: videoInfo.name, | ||
173 | remote: false, | ||
174 | extname: extname(videoPhysicalFile.filename), | ||
175 | category: videoInfo.category, | ||
176 | licence: videoInfo.licence, | ||
177 | language: videoInfo.language, | ||
178 | nsfw: videoInfo.nsfw, | ||
179 | description: videoInfo.description, | ||
180 | privacy: videoInfo.privacy, | ||
181 | duration: videoPhysicalFile['duration'], // duration was added by a previous middleware | ||
182 | channelId: res.locals.videoChannel.id | ||
183 | } | ||
184 | const video = db.Video.build(videoData) | ||
185 | video.url = getVideoActivityPubUrl(video) | ||
172 | 186 | ||
173 | const videoData = { | 187 | const videoFilePath = join(CONFIG.STORAGE.VIDEOS_DIR, videoPhysicalFile.filename) |
174 | name: videoInfo.name, | 188 | const videoFileHeight = await getVideoFileHeight(videoFilePath) |
175 | remote: false, | ||
176 | extname: extname(videoPhysicalFile.filename), | ||
177 | category: videoInfo.category, | ||
178 | licence: videoInfo.licence, | ||
179 | language: videoInfo.language, | ||
180 | nsfw: videoInfo.nsfw, | ||
181 | description: videoInfo.description, | ||
182 | privacy: videoInfo.privacy, | ||
183 | duration: videoPhysicalFile['duration'], // duration was added by a previous middleware | ||
184 | channelId: res.locals.videoChannel.id | ||
185 | } | ||
186 | const video = db.Video.build(videoData) | ||
187 | video.url = getVideoActivityPubUrl(video) | ||
188 | 189 | ||
189 | const videoFilePath = join(CONFIG.STORAGE.VIDEOS_DIR, videoPhysicalFile.filename) | 190 | const videoFileData = { |
190 | const videoFileHeight = await getVideoFileHeight(videoFilePath) | 191 | extname: extname(videoPhysicalFile.filename), |
192 | resolution: videoFileHeight, | ||
193 | size: videoPhysicalFile.size | ||
194 | } | ||
195 | const videoFile = db.VideoFile.build(videoFileData) | ||
196 | const videoDir = CONFIG.STORAGE.VIDEOS_DIR | ||
197 | const source = join(videoDir, videoPhysicalFile.filename) | ||
198 | const destination = join(videoDir, video.getVideoFilename(videoFile)) | ||
191 | 199 | ||
192 | const videoFileData = { | 200 | await renamePromise(source, destination) |
193 | extname: extname(videoPhysicalFile.filename), | 201 | // This is important in case if there is another attempt in the retry process |
194 | resolution: videoFileHeight, | 202 | videoPhysicalFile.filename = video.getVideoFilename(videoFile) |
195 | size: videoPhysicalFile.size | ||
196 | } | ||
197 | const videoFile = db.VideoFile.build(videoFileData) | ||
198 | const videoDir = CONFIG.STORAGE.VIDEOS_DIR | ||
199 | const source = join(videoDir, videoPhysicalFile.filename) | ||
200 | const destination = join(videoDir, video.getVideoFilename(videoFile)) | ||
201 | 203 | ||
202 | await renamePromise(source, destination) | 204 | const tasks = [] |
203 | // This is important in case if there is another attempt in the retry process | ||
204 | videoPhysicalFile.filename = video.getVideoFilename(videoFile) | ||
205 | 205 | ||
206 | const tasks = [] | 206 | tasks.push( |
207 | video.createTorrentAndSetInfoHash(videoFile), | ||
208 | video.createThumbnail(videoFile), | ||
209 | video.createPreview(videoFile) | ||
210 | ) | ||
211 | await Promise.all(tasks) | ||
207 | 212 | ||
208 | tasks.push( | 213 | return db.sequelize.transaction(async t => { |
209 | video.createTorrentAndSetInfoHash(videoFile), | 214 | const sequelizeOptions = { transaction: t } |
210 | video.createThumbnail(videoFile), | ||
211 | video.createPreview(videoFile) | ||
212 | ) | ||
213 | 215 | ||
214 | if (CONFIG.TRANSCODING.ENABLED === true) { | 216 | if (CONFIG.TRANSCODING.ENABLED === true) { |
215 | // Put uuid because we don't have id auto incremented for now | 217 | // Put uuid because we don't have id auto incremented for now |
@@ -217,21 +219,17 @@ async function addVideo (req: express.Request, res: express.Response, videoPhysi | |||
217 | videoUUID: video.uuid | 219 | videoUUID: video.uuid |
218 | } | 220 | } |
219 | 221 | ||
220 | tasks.push( | 222 | await transcodingJobScheduler.createJob(t, 'videoFileOptimizer', dataInput) |
221 | transcodingJobScheduler.createJob(t, 'videoFileOptimizer', dataInput) | ||
222 | ) | ||
223 | } | 223 | } |
224 | await Promise.all(tasks) | ||
225 | 224 | ||
226 | const videoCreated = await video.save(sequelizeOptions) | 225 | const videoCreated = await video.save(sequelizeOptions) |
227 | // Do not forget to add video channel information to the created video | 226 | // Do not forget to add video channel information to the created video |
228 | videoCreated.VideoChannel = res.locals.videoChannel | 227 | videoCreated.VideoChannel = res.locals.videoChannel |
229 | videoUUID = videoCreated.uuid | ||
230 | 228 | ||
231 | videoFile.videoId = video.id | 229 | videoFile.videoId = video.id |
232 | |||
233 | await videoFile.save(sequelizeOptions) | 230 | await videoFile.save(sequelizeOptions) |
234 | video.VideoFiles = [videoFile] | 231 | |
232 | video.VideoFiles = [ videoFile ] | ||
235 | 233 | ||
236 | if (videoInfo.tags) { | 234 | if (videoInfo.tags) { |
237 | const tagInstances = await db.Tag.findOrCreateTags(videoInfo.tags, t) | 235 | const tagInstances = await db.Tag.findOrCreateTags(videoInfo.tags, t) |
@@ -241,15 +239,17 @@ async function addVideo (req: express.Request, res: express.Response, videoPhysi | |||
241 | } | 239 | } |
242 | 240 | ||
243 | // Let transcoding job send the video to friends because the video file extension might change | 241 | // Let transcoding job send the video to friends because the video file extension might change |
244 | if (CONFIG.TRANSCODING.ENABLED === true) return undefined | 242 | if (CONFIG.TRANSCODING.ENABLED === true) return videoCreated |
245 | // Don't send video to remote servers, it is private | 243 | // Don't send video to remote servers, it is private |
246 | if (video.privacy === VideoPrivacy.PRIVATE) return undefined | 244 | if (video.privacy === VideoPrivacy.PRIVATE) return videoCreated |
247 | 245 | ||
248 | await sendAddVideo(video, t) | 246 | await sendAddVideo(video, t) |
249 | await shareVideoByServer(video, t) | 247 | await shareVideoByServer(video, t) |
250 | }) | ||
251 | 248 | ||
252 | logger.info('Video with name %s and uuid %s created.', videoInfo.name, videoUUID) | 249 | logger.info('Video with name %s and uuid %s created.', videoInfo.name, videoCreated.uuid) |
250 | |||
251 | return videoCreated | ||
252 | }) | ||
253 | } | 253 | } |
254 | 254 | ||
255 | async function updateVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) { | 255 | async function updateVideoRetryWrapper (req: express.Request, res: express.Response, next: express.NextFunction) { |
@@ -280,7 +280,7 @@ async function updateVideo (req: express.Request, res: express.Response) { | |||
280 | if (videoInfoToUpdate.licence !== undefined) videoInstance.set('licence', videoInfoToUpdate.licence) | 280 | if (videoInfoToUpdate.licence !== undefined) videoInstance.set('licence', videoInfoToUpdate.licence) |
281 | if (videoInfoToUpdate.language !== undefined) videoInstance.set('language', videoInfoToUpdate.language) | 281 | if (videoInfoToUpdate.language !== undefined) videoInstance.set('language', videoInfoToUpdate.language) |
282 | if (videoInfoToUpdate.nsfw !== undefined) videoInstance.set('nsfw', videoInfoToUpdate.nsfw) | 282 | if (videoInfoToUpdate.nsfw !== undefined) videoInstance.set('nsfw', videoInfoToUpdate.nsfw) |
283 | if (videoInfoToUpdate.privacy !== undefined) videoInstance.set('privacy', videoInfoToUpdate.privacy) | 283 | if (videoInfoToUpdate.privacy !== undefined) videoInstance.set('privacy', parseInt(videoInfoToUpdate.privacy.toString(), 10)) |
284 | if (videoInfoToUpdate.description !== undefined) videoInstance.set('description', videoInfoToUpdate.description) | 284 | if (videoInfoToUpdate.description !== undefined) videoInstance.set('description', videoInfoToUpdate.description) |
285 | 285 | ||
286 | const videoInstanceUpdated = await videoInstance.save(sequelizeOptions) | 286 | const videoInstanceUpdated = await videoInstance.save(sequelizeOptions) |
@@ -298,9 +298,9 @@ async function updateVideo (req: express.Request, res: express.Response) { | |||
298 | } | 298 | } |
299 | 299 | ||
300 | // Video is not private anymore, send a create action to remote servers | 300 | // Video is not private anymore, send a create action to remote servers |
301 | if (wasPrivateVideo === true && videoInstance.privacy !== VideoPrivacy.PRIVATE) { | 301 | if (wasPrivateVideo === true && videoInstanceUpdated.privacy !== VideoPrivacy.PRIVATE) { |
302 | await sendAddVideo(videoInstance, t) | 302 | await sendAddVideo(videoInstanceUpdated, t) |
303 | await shareVideoByServer(videoInstance, t) | 303 | await shareVideoByServer(videoInstanceUpdated, t) |
304 | } | 304 | } |
305 | }) | 305 | }) |
306 | 306 | ||
@@ -378,8 +378,7 @@ async function removeVideo (req: express.Request, res: express.Response) { | |||
378 | 378 | ||
379 | async function searchVideos (req: express.Request, res: express.Response, next: express.NextFunction) { | 379 | async function searchVideos (req: express.Request, res: express.Response, next: express.NextFunction) { |
380 | const resultList = await db.Video.searchAndPopulateAccountAndServerAndTags( | 380 | const resultList = await db.Video.searchAndPopulateAccountAndServerAndTags( |
381 | req.params.value, | 381 | req.query.search, |
382 | req.query.field, | ||
383 | req.query.start, | 382 | req.query.start, |
384 | req.query.count, | 383 | req.query.count, |
385 | req.query.sort | 384 | req.query.sort |