diff options
author | Rigel Kent <sendmemail@rigelk.eu> | 2020-03-10 14:39:40 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-10 14:39:40 +0100 |
commit | 8319d6ae72d4da6de51bd3d4b5c68040fc8dc3b4 (patch) | |
tree | 1f87041b2cd76222844960602cdc9f52fe206c7b /server/helpers | |
parent | edb868655e52f934a71141175cf9dc6cb4753e11 (diff) | |
download | PeerTube-8319d6ae72d4da6de51bd3d4b5c68040fc8dc3b4.tar.gz PeerTube-8319d6ae72d4da6de51bd3d4b5c68040fc8dc3b4.tar.zst PeerTube-8319d6ae72d4da6de51bd3d4b5c68040fc8dc3b4.zip |
Add video file metadata to download modal, via ffprobe (#2411)
* Add video file metadata via ffprobe
* Federate video file metadata
* Add tests for file metadata generation
* Complete tests for videoFile metadata federation
* Lint migration and video-file for metadata
* Objectify metadata from getter in ffmpeg-utils
* Add metadataUrl to all videoFiles
* Simplify metadata API middleware
* Load playlist in videoFile when requesting metadata
Diffstat (limited to 'server/helpers')
-rw-r--r-- | server/helpers/ffmpeg-utils.ts | 33 | ||||
-rw-r--r-- | server/helpers/middlewares/videos.ts | 14 |
2 files changed, 27 insertions, 20 deletions
diff --git a/server/helpers/ffmpeg-utils.ts b/server/helpers/ffmpeg-utils.ts index 084516e55..5ee295635 100644 --- a/server/helpers/ffmpeg-utils.ts +++ b/server/helpers/ffmpeg-utils.ts | |||
@@ -7,6 +7,7 @@ import { logger } from './logger' | |||
7 | import { checkFFmpegEncoders } from '../initializers/checker-before-init' | 7 | import { checkFFmpegEncoders } from '../initializers/checker-before-init' |
8 | import { readFile, remove, writeFile } from 'fs-extra' | 8 | import { readFile, remove, writeFile } from 'fs-extra' |
9 | import { CONFIG } from '../initializers/config' | 9 | import { CONFIG } from '../initializers/config' |
10 | import { VideoFileMetadata } from '@shared/models/videos/video-file-metadata' | ||
10 | 11 | ||
11 | /** | 12 | /** |
12 | * A toolbox to play with audio | 13 | * A toolbox to play with audio |
@@ -169,24 +170,26 @@ async function getVideoFileFPS (path: string) { | |||
169 | return 0 | 170 | return 0 |
170 | } | 171 | } |
171 | 172 | ||
172 | async function getVideoFileBitrate (path: string) { | 173 | async function getMetadataFromFile<T> (path: string, cb = metadata => metadata) { |
173 | return new Promise<number>((res, rej) => { | 174 | return new Promise<T>((res, rej) => { |
174 | ffmpeg.ffprobe(path, (err, metadata) => { | 175 | ffmpeg.ffprobe(path, (err, metadata) => { |
175 | if (err) return rej(err) | 176 | if (err) return rej(err) |
176 | 177 | ||
177 | return res(metadata.format.bit_rate) | 178 | return res(cb(new VideoFileMetadata(metadata))) |
178 | }) | 179 | }) |
179 | }) | 180 | }) |
180 | } | 181 | } |
181 | 182 | ||
183 | async function getVideoFileBitrate (path: string) { | ||
184 | return getMetadataFromFile<number>(path, metadata => metadata.format.bit_rate) | ||
185 | } | ||
186 | |||
182 | function getDurationFromVideoFile (path: string) { | 187 | function getDurationFromVideoFile (path: string) { |
183 | return new Promise<number>((res, rej) => { | 188 | return getMetadataFromFile<number>(path, metadata => Math.floor(metadata.format.duration)) |
184 | ffmpeg.ffprobe(path, (err, metadata) => { | 189 | } |
185 | if (err) return rej(err) | ||
186 | 190 | ||
187 | return res(Math.floor(metadata.format.duration)) | 191 | function getVideoStreamFromFile (path: string) { |
188 | }) | 192 | return getMetadataFromFile<any>(path, metadata => metadata.streams.find(s => s.codec_type === 'video') || null) |
189 | }) | ||
190 | } | 193 | } |
191 | 194 | ||
192 | async function generateImageFromVideoFile (fromPath: string, folder: string, imageName: string, size: { width: number, height: number }) { | 195 | async function generateImageFromVideoFile (fromPath: string, folder: string, imageName: string, size: { width: number, height: number }) { |
@@ -341,6 +344,7 @@ export { | |||
341 | getAudioStreamCodec, | 344 | getAudioStreamCodec, |
342 | getVideoStreamSize, | 345 | getVideoStreamSize, |
343 | getVideoFileResolution, | 346 | getVideoFileResolution, |
347 | getMetadataFromFile, | ||
344 | getDurationFromVideoFile, | 348 | getDurationFromVideoFile, |
345 | generateImageFromVideoFile, | 349 | generateImageFromVideoFile, |
346 | TranscodeOptions, | 350 | TranscodeOptions, |
@@ -450,17 +454,6 @@ async function fixHLSPlaylistIfNeeded (options: TranscodeOptions) { | |||
450 | await writeFile(options.outputPath, newContent) | 454 | await writeFile(options.outputPath, newContent) |
451 | } | 455 | } |
452 | 456 | ||
453 | function getVideoStreamFromFile (path: string) { | ||
454 | return new Promise<any>((res, rej) => { | ||
455 | ffmpeg.ffprobe(path, (err, metadata) => { | ||
456 | if (err) return rej(err) | ||
457 | |||
458 | const videoStream = metadata.streams.find(s => s.codec_type === 'video') | ||
459 | return res(videoStream || null) | ||
460 | }) | ||
461 | }) | ||
462 | } | ||
463 | |||
464 | /** | 457 | /** |
465 | * A slightly customised version of the 'veryfast' x264 preset | 458 | * A slightly customised version of the 'veryfast' x264 preset |
466 | * | 459 | * |
diff --git a/server/helpers/middlewares/videos.ts b/server/helpers/middlewares/videos.ts index 409f78650..a0bbcdb21 100644 --- a/server/helpers/middlewares/videos.ts +++ b/server/helpers/middlewares/videos.ts | |||
@@ -12,6 +12,7 @@ import { | |||
12 | MVideoThumbnail, | 12 | MVideoThumbnail, |
13 | MVideoWithRights | 13 | MVideoWithRights |
14 | } from '@server/typings/models' | 14 | } from '@server/typings/models' |
15 | import { VideoFileModel } from '@server/models/video/video-file' | ||
15 | 16 | ||
16 | async function doesVideoExist (id: number | string, res: Response, fetchType: VideoFetchType = 'all') { | 17 | async function doesVideoExist (id: number | string, res: Response, fetchType: VideoFetchType = 'all') { |
17 | const userId = res.locals.oauth ? res.locals.oauth.token.User.id : undefined | 18 | const userId = res.locals.oauth ? res.locals.oauth.token.User.id : undefined |
@@ -51,6 +52,18 @@ async function doesVideoExist (id: number | string, res: Response, fetchType: Vi | |||
51 | return true | 52 | return true |
52 | } | 53 | } |
53 | 54 | ||
55 | async function doesVideoFileOfVideoExist (id: number, videoIdOrUUID: number | string, res: Response) { | ||
56 | if (!await VideoFileModel.doesVideoExistForVideoFile(id, videoIdOrUUID)) { | ||
57 | res.status(404) | ||
58 | .json({ error: 'VideoFile matching Video not found' }) | ||
59 | .end() | ||
60 | |||
61 | return false | ||
62 | } | ||
63 | |||
64 | return true | ||
65 | } | ||
66 | |||
54 | async function doesVideoChannelOfAccountExist (channelId: number, user: MUserAccountId, res: Response) { | 67 | async function doesVideoChannelOfAccountExist (channelId: number, user: MUserAccountId, res: Response) { |
55 | if (user.hasRight(UserRight.UPDATE_ANY_VIDEO) === true) { | 68 | if (user.hasRight(UserRight.UPDATE_ANY_VIDEO) === true) { |
56 | const videoChannel = await VideoChannelModel.loadAndPopulateAccount(channelId) | 69 | const videoChannel = await VideoChannelModel.loadAndPopulateAccount(channelId) |
@@ -107,5 +120,6 @@ function checkUserCanManageVideo (user: MUser, video: MVideoAccountLight, right: | |||
107 | export { | 120 | export { |
108 | doesVideoChannelOfAccountExist, | 121 | doesVideoChannelOfAccountExist, |
109 | doesVideoExist, | 122 | doesVideoExist, |
123 | doesVideoFileOfVideoExist, | ||
110 | checkUserCanManageVideo | 124 | checkUserCanManageVideo |
111 | } | 125 | } |