aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/helpers
diff options
context:
space:
mode:
authorRigel Kent <sendmemail@rigelk.eu>2020-03-10 14:39:40 +0100
committerGitHub <noreply@github.com>2020-03-10 14:39:40 +0100
commit8319d6ae72d4da6de51bd3d4b5c68040fc8dc3b4 (patch)
tree1f87041b2cd76222844960602cdc9f52fe206c7b /server/helpers
parentedb868655e52f934a71141175cf9dc6cb4753e11 (diff)
downloadPeerTube-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.ts33
-rw-r--r--server/helpers/middlewares/videos.ts14
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'
7import { checkFFmpegEncoders } from '../initializers/checker-before-init' 7import { checkFFmpegEncoders } from '../initializers/checker-before-init'
8import { readFile, remove, writeFile } from 'fs-extra' 8import { readFile, remove, writeFile } from 'fs-extra'
9import { CONFIG } from '../initializers/config' 9import { CONFIG } from '../initializers/config'
10import { 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
172async function getVideoFileBitrate (path: string) { 173async 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
183async function getVideoFileBitrate (path: string) {
184 return getMetadataFromFile<number>(path, metadata => metadata.format.bit_rate)
185}
186
182function getDurationFromVideoFile (path: string) { 187function 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)) 191function getVideoStreamFromFile (path: string) {
188 }) 192 return getMetadataFromFile<any>(path, metadata => metadata.streams.find(s => s.codec_type === 'video') || null)
189 })
190} 193}
191 194
192async function generateImageFromVideoFile (fromPath: string, folder: string, imageName: string, size: { width: number, height: number }) { 195async 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
453function 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'
15import { VideoFileModel } from '@server/models/video/video-file'
15 16
16async function doesVideoExist (id: number | string, res: Response, fetchType: VideoFetchType = 'all') { 17async 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
55async 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
54async function doesVideoChannelOfAccountExist (channelId: number, user: MUserAccountId, res: Response) { 67async 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:
107export { 120export {
108 doesVideoChannelOfAccountExist, 121 doesVideoChannelOfAccountExist,
109 doesVideoExist, 122 doesVideoExist,
123 doesVideoFileOfVideoExist,
110 checkUserCanManageVideo 124 checkUserCanManageVideo
111} 125}