1 import { CONFIG } from '../initializers'
2 import { extname, join } from 'path'
3 import { getVideoFileFPS, getVideoFileResolution, transcode } from '../helpers/ffmpeg-utils'
4 import { copy, remove, rename, stat } from 'fs-extra'
5 import { logger } from '../helpers/logger'
6 import { VideoResolution } from '../../shared/models/videos'
7 import { VideoFileModel } from '../models/video/video-file'
8 import { VideoModel } from '../models/video/video'
10 async function optimizeVideofile (video: VideoModel, inputVideoFileArg?: VideoFileModel) {
11 const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR
12 const newExtname = '.mp4'
14 const inputVideoFile = inputVideoFileArg ? inputVideoFileArg : video.getOriginalFile()
15 const videoInputPath = join(videosDirectory, video.getVideoFilename(inputVideoFile))
16 const videoTranscodedPath = join(videosDirectory, video.id + '-transcoded' + newExtname)
18 const transcodeOptions = {
19 inputPath: videoInputPath,
20 outputPath: videoTranscodedPath
23 // Could be very long!
24 await transcode(transcodeOptions)
27 await remove(videoInputPath)
29 // Important to do this before getVideoFilename() to take in account the new file extension
30 inputVideoFile.set('extname', newExtname)
32 const videoOutputPath = video.getVideoFilePath(inputVideoFile)
33 await rename(videoTranscodedPath, videoOutputPath)
34 const stats = await stat(videoOutputPath)
35 const fps = await getVideoFileFPS(videoOutputPath)
37 inputVideoFile.set('size', stats.size)
38 inputVideoFile.set('fps', fps)
40 await video.createTorrentAndSetInfoHash(inputVideoFile)
41 await inputVideoFile.save()
43 // Auto destruction...
44 video.destroy().catch(err => logger.error('Cannot destruct video after transcoding failure.', { err }))
50 async function transcodeOriginalVideofile (video: VideoModel, resolution: VideoResolution, isPortraitMode: boolean) {
51 const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR
52 const extname = '.mp4'
54 // We are sure it's x264 in mp4 because optimizeOriginalVideofile was already executed
55 const videoInputPath = join(videosDirectory, video.getVideoFilename(video.getOriginalFile()))
57 const newVideoFile = new VideoFileModel({
63 const videoOutputPath = join(videosDirectory, video.getVideoFilename(newVideoFile))
65 const transcodeOptions = {
66 inputPath: videoInputPath,
67 outputPath: videoOutputPath,
72 await transcode(transcodeOptions)
74 const stats = await stat(videoOutputPath)
75 const fps = await getVideoFileFPS(videoOutputPath)
77 newVideoFile.set('size', stats.size)
78 newVideoFile.set('fps', fps)
80 await video.createTorrentAndSetInfoHash(newVideoFile)
82 await newVideoFile.save()
84 video.VideoFiles.push(newVideoFile)
87 async function importVideoFile (video: VideoModel, inputFilePath: string) {
88 const { videoFileResolution } = await getVideoFileResolution(inputFilePath)
89 const { size } = await stat(inputFilePath)
90 const fps = await getVideoFileFPS(inputFilePath)
92 let updatedVideoFile = new VideoFileModel({
93 resolution: videoFileResolution,
94 extname: extname(inputFilePath),
100 const currentVideoFile = video.VideoFiles.find(videoFile => videoFile.resolution === updatedVideoFile.resolution)
102 if (currentVideoFile) {
103 // Remove old file and old torrent
104 await video.removeFile(currentVideoFile)
105 await video.removeTorrent(currentVideoFile)
106 // Remove the old video file from the array
107 video.VideoFiles = video.VideoFiles.filter(f => f !== currentVideoFile)
109 // Update the database
110 currentVideoFile.set('extname', updatedVideoFile.extname)
111 currentVideoFile.set('size', updatedVideoFile.size)
112 currentVideoFile.set('fps', updatedVideoFile.fps)
114 updatedVideoFile = currentVideoFile
117 const outputPath = video.getVideoFilePath(updatedVideoFile)
118 await copy(inputFilePath, outputPath)
120 await video.createTorrentAndSetInfoHash(updatedVideoFile)
122 await updatedVideoFile.save()
124 video.VideoFiles.push(updatedVideoFile)
129 transcodeOriginalVideofile,