diff options
Diffstat (limited to 'server/controllers/api/videos/index.ts')
-rw-r--r-- | server/controllers/api/videos/index.ts | 55 |
1 files changed, 23 insertions, 32 deletions
diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts index 8d4ff07eb..8048c568c 100644 --- a/server/controllers/api/videos/index.ts +++ b/server/controllers/api/videos/index.ts | |||
@@ -1,10 +1,10 @@ | |||
1 | import * as express from 'express' | 1 | import * as express from 'express' |
2 | import { extname } from 'path' | 2 | import { extname } from 'path' |
3 | import { VideoCreate, VideoPrivacy, VideoState, VideoUpdate } from '../../../../shared' | 3 | import { VideoCreate, VideoPrivacy, VideoState, VideoUpdate } from '../../../../shared' |
4 | import { getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffmpeg-utils' | 4 | import { getMetadataFromFile, getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffmpeg-utils' |
5 | import { logger } from '../../../helpers/logger' | 5 | import { logger } from '../../../helpers/logger' |
6 | import { auditLoggerFactory, getAuditIdFromRes, VideoAuditView } from '../../../helpers/audit-logger' | 6 | import { auditLoggerFactory, getAuditIdFromRes, VideoAuditView } from '../../../helpers/audit-logger' |
7 | import { getFormattedObjects, getServerActor } from '../../../helpers/utils' | 7 | import { getFormattedObjects } from '../../../helpers/utils' |
8 | import { autoBlacklistVideoIfNeeded } from '../../../lib/video-blacklist' | 8 | import { autoBlacklistVideoIfNeeded } from '../../../lib/video-blacklist' |
9 | import { | 9 | import { |
10 | DEFAULT_AUDIO_RESOLUTION, | 10 | DEFAULT_AUDIO_RESOLUTION, |
@@ -14,12 +14,7 @@ import { | |||
14 | VIDEO_LICENCES, | 14 | VIDEO_LICENCES, |
15 | VIDEO_PRIVACIES | 15 | VIDEO_PRIVACIES |
16 | } from '../../../initializers/constants' | 16 | } from '../../../initializers/constants' |
17 | import { | 17 | import { federateVideoIfNeeded, fetchRemoteVideoDescription } from '../../../lib/activitypub/videos' |
18 | changeVideoChannelShare, | ||
19 | federateVideoIfNeeded, | ||
20 | fetchRemoteVideoDescription, | ||
21 | getVideoActivityPubUrl | ||
22 | } from '../../../lib/activitypub' | ||
23 | import { JobQueue } from '../../../lib/job-queue' | 18 | import { JobQueue } from '../../../lib/job-queue' |
24 | import { Redis } from '../../../lib/redis' | 19 | import { Redis } from '../../../lib/redis' |
25 | import { | 20 | import { |
@@ -32,6 +27,7 @@ import { | |||
32 | paginationValidator, | 27 | paginationValidator, |
33 | setDefaultPagination, | 28 | setDefaultPagination, |
34 | setDefaultSort, | 29 | setDefaultSort, |
30 | videoFileMetadataGetValidator, | ||
35 | videosAddValidator, | 31 | videosAddValidator, |
36 | videosCustomGetValidator, | 32 | videosCustomGetValidator, |
37 | videosGetValidator, | 33 | videosGetValidator, |
@@ -61,11 +57,15 @@ import { CONFIG } from '../../../initializers/config' | |||
61 | import { sequelizeTypescript } from '../../../initializers/database' | 57 | import { sequelizeTypescript } from '../../../initializers/database' |
62 | import { createVideoMiniatureFromExisting, generateVideoMiniature } from '../../../lib/thumbnail' | 58 | import { createVideoMiniatureFromExisting, generateVideoMiniature } from '../../../lib/thumbnail' |
63 | import { ThumbnailType } from '../../../../shared/models/videos/thumbnail.type' | 59 | import { ThumbnailType } from '../../../../shared/models/videos/thumbnail.type' |
64 | import { VideoTranscodingPayload } from '../../../lib/job-queue/handlers/video-transcoding' | ||
65 | import { Hooks } from '../../../lib/plugins/hooks' | 60 | import { Hooks } from '../../../lib/plugins/hooks' |
66 | import { MVideoDetails, MVideoFullLight } from '@server/typings/models' | 61 | import { MVideoDetails, MVideoFullLight } from '@server/typings/models' |
67 | import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent' | 62 | import { createTorrentAndSetInfoHash } from '@server/helpers/webtorrent' |
68 | import { getVideoFilePath } from '@server/lib/video-paths' | 63 | import { getVideoFilePath } from '@server/lib/video-paths' |
64 | import toInt from 'validator/lib/toInt' | ||
65 | import { addOptimizeOrMergeAudioJob } from '@server/helpers/video' | ||
66 | import { getServerActor } from '@server/models/application/application' | ||
67 | import { changeVideoChannelShare } from '@server/lib/activitypub/share' | ||
68 | import { getVideoActivityPubUrl } from '@server/lib/activitypub/url' | ||
69 | 69 | ||
70 | const auditLogger = auditLoggerFactory('videos') | 70 | const auditLogger = auditLoggerFactory('videos') |
71 | const videosRouter = express.Router() | 71 | const videosRouter = express.Router() |
@@ -128,6 +128,10 @@ videosRouter.get('/:id/description', | |||
128 | asyncMiddleware(videosGetValidator), | 128 | asyncMiddleware(videosGetValidator), |
129 | asyncMiddleware(getVideoDescription) | 129 | asyncMiddleware(getVideoDescription) |
130 | ) | 130 | ) |
131 | videosRouter.get('/:id/metadata/:videoFileId', | ||
132 | asyncMiddleware(videoFileMetadataGetValidator), | ||
133 | asyncMiddleware(getVideoFileMetadata) | ||
134 | ) | ||
131 | videosRouter.get('/:id', | 135 | videosRouter.get('/:id', |
132 | optionalAuthenticate, | 136 | optionalAuthenticate, |
133 | asyncMiddleware(videosCustomGetValidator('only-video-with-rights')), | 137 | asyncMiddleware(videosCustomGetValidator('only-video-with-rights')), |
@@ -135,7 +139,7 @@ videosRouter.get('/:id', | |||
135 | asyncMiddleware(getVideo) | 139 | asyncMiddleware(getVideo) |
136 | ) | 140 | ) |
137 | videosRouter.post('/:id/views', | 141 | videosRouter.post('/:id/views', |
138 | asyncMiddleware(videosGetValidator), | 142 | asyncMiddleware(videosCustomGetValidator('only-immutable-attributes')), |
139 | asyncMiddleware(viewVideo) | 143 | asyncMiddleware(viewVideo) |
140 | ) | 144 | ) |
141 | 145 | ||
@@ -206,7 +210,8 @@ async function addVideo (req: express.Request, res: express.Response) { | |||
206 | const videoFile = new VideoFileModel({ | 210 | const videoFile = new VideoFileModel({ |
207 | extname: extname(videoPhysicalFile.filename), | 211 | extname: extname(videoPhysicalFile.filename), |
208 | size: videoPhysicalFile.size, | 212 | size: videoPhysicalFile.size, |
209 | videoStreamingPlaylistId: null | 213 | videoStreamingPlaylistId: null, |
214 | metadata: await getMetadataFromFile<any>(videoPhysicalFile.path) | ||
210 | }) | 215 | }) |
211 | 216 | ||
212 | if (videoFile.isAudio()) { | 217 | if (videoFile.isAudio()) { |
@@ -289,25 +294,7 @@ async function addVideo (req: express.Request, res: express.Response) { | |||
289 | Notifier.Instance.notifyOnNewVideoIfNeeded(videoCreated) | 294 | Notifier.Instance.notifyOnNewVideoIfNeeded(videoCreated) |
290 | 295 | ||
291 | if (video.state === VideoState.TO_TRANSCODE) { | 296 | if (video.state === VideoState.TO_TRANSCODE) { |
292 | // Put uuid because we don't have id auto incremented for now | 297 | await addOptimizeOrMergeAudioJob(videoCreated, videoFile) |
293 | let dataInput: VideoTranscodingPayload | ||
294 | |||
295 | if (videoFile.isAudio()) { | ||
296 | dataInput = { | ||
297 | type: 'merge-audio' as 'merge-audio', | ||
298 | resolution: DEFAULT_AUDIO_RESOLUTION, | ||
299 | videoUUID: videoCreated.uuid, | ||
300 | isNewVideo: true | ||
301 | } | ||
302 | } else { | ||
303 | dataInput = { | ||
304 | type: 'optimize' as 'optimize', | ||
305 | videoUUID: videoCreated.uuid, | ||
306 | isNewVideo: true | ||
307 | } | ||
308 | } | ||
309 | |||
310 | await JobQueue.Instance.createJob({ type: 'video-transcoding', payload: dataInput }) | ||
311 | } | 298 | } |
312 | 299 | ||
313 | Hooks.runAction('action:api.video.uploaded', { video: videoCreated }) | 300 | Hooks.runAction('action:api.video.uploaded', { video: videoCreated }) |
@@ -452,14 +439,13 @@ async function getVideo (req: express.Request, res: express.Response) { | |||
452 | 439 | ||
453 | if (video.isOutdated()) { | 440 | if (video.isOutdated()) { |
454 | JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video', url: video.url } }) | 441 | JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video', url: video.url } }) |
455 | .catch(err => logger.error('Cannot create AP refresher job for video %s.', video.url, { err })) | ||
456 | } | 442 | } |
457 | 443 | ||
458 | return res.json(video.toFormattedDetailsJSON()) | 444 | return res.json(video.toFormattedDetailsJSON()) |
459 | } | 445 | } |
460 | 446 | ||
461 | async function viewVideo (req: express.Request, res: express.Response) { | 447 | async function viewVideo (req: express.Request, res: express.Response) { |
462 | const videoInstance = res.locals.videoAll | 448 | const videoInstance = res.locals.onlyImmutableVideo |
463 | 449 | ||
464 | const ip = req.ip | 450 | const ip = req.ip |
465 | const exists = await Redis.Instance.doesVideoIPViewExist(ip, videoInstance.uuid) | 451 | const exists = await Redis.Instance.doesVideoIPViewExist(ip, videoInstance.uuid) |
@@ -494,6 +480,11 @@ async function getVideoDescription (req: express.Request, res: express.Response) | |||
494 | return res.json({ description }) | 480 | return res.json({ description }) |
495 | } | 481 | } |
496 | 482 | ||
483 | async function getVideoFileMetadata (req: express.Request, res: express.Response) { | ||
484 | const videoFile = await VideoFileModel.loadWithMetadata(toInt(req.params.videoFileId)) | ||
485 | return res.json(videoFile.metadata) | ||
486 | } | ||
487 | |||
497 | async function listVideos (req: express.Request, res: express.Response) { | 488 | async function listVideos (req: express.Request, res: express.Response) { |
498 | const countVideos = getCountVideos(req) | 489 | const countVideos = getCountVideos(req) |
499 | 490 | ||