diff options
Diffstat (limited to 'server/lib/job-queue/handlers/video-live-ending.ts')
-rw-r--r-- | server/lib/job-queue/handlers/video-live-ending.ts | 67 |
1 files changed, 24 insertions, 43 deletions
diff --git a/server/lib/job-queue/handlers/video-live-ending.ts b/server/lib/job-queue/handlers/video-live-ending.ts index 6e1076d8f..55bee0b83 100644 --- a/server/lib/job-queue/handlers/video-live-ending.ts +++ b/server/lib/job-queue/handlers/video-live-ending.ts | |||
@@ -1,13 +1,12 @@ | |||
1 | import * as Bull from 'bull' | 1 | import * as Bull from 'bull' |
2 | import { copy, readdir, remove } from 'fs-extra' | 2 | import { copy, readdir, remove } from 'fs-extra' |
3 | import { join } from 'path' | 3 | import { join } from 'path' |
4 | import { hlsPlaylistToFragmentedMP4 } from '@server/helpers/ffmpeg-utils' | ||
5 | import { getDurationFromVideoFile, getVideoFileResolution } from '@server/helpers/ffprobe-utils' | 4 | import { getDurationFromVideoFile, getVideoFileResolution } from '@server/helpers/ffprobe-utils' |
6 | import { VIDEO_LIVE } from '@server/initializers/constants' | 5 | import { VIDEO_LIVE } from '@server/initializers/constants' |
7 | import { generateVideoMiniature } from '@server/lib/thumbnail' | 6 | import { generateVideoMiniature } from '@server/lib/thumbnail' |
8 | import { publishAndFederateIfNeeded } from '@server/lib/video' | 7 | import { publishAndFederateIfNeeded } from '@server/lib/video' |
9 | import { getHLSDirectory } from '@server/lib/video-paths' | 8 | import { getHLSDirectory } from '@server/lib/video-paths' |
10 | import { generateHlsPlaylist } from '@server/lib/video-transcoding' | 9 | import { generateHlsPlaylistFromTS } from '@server/lib/video-transcoding' |
11 | import { VideoModel } from '@server/models/video/video' | 10 | import { VideoModel } from '@server/models/video/video' |
12 | import { VideoFileModel } from '@server/models/video/video-file' | 11 | import { VideoFileModel } from '@server/models/video/video-file' |
13 | import { VideoLiveModel } from '@server/models/video/video-live' | 12 | import { VideoLiveModel } from '@server/models/video/video-live' |
@@ -71,32 +70,6 @@ async function saveLive (video: MVideo, live: MVideoLive) { | |||
71 | } | 70 | } |
72 | } | 71 | } |
73 | 72 | ||
74 | const replayFiles = await readdir(replayDirectory) | ||
75 | |||
76 | const resolutions: number[] = [] | ||
77 | let duration: number | ||
78 | |||
79 | for (const playlistFile of playlistFiles) { | ||
80 | const playlistPath = join(replayDirectory, playlistFile) | ||
81 | const { videoFileResolution } = await getVideoFileResolution(playlistPath) | ||
82 | |||
83 | // Put the final mp4 in the hls directory, and not in the replay directory | ||
84 | const mp4TmpPath = buildMP4TmpPath(hlsDirectory, videoFileResolution) | ||
85 | |||
86 | // Playlist name is for example 3.m3u8 | ||
87 | // Segments names are 3-0.ts 3-1.ts etc | ||
88 | const shouldStartWith = playlistFile.replace(/\.m3u8$/, '') + '-' | ||
89 | |||
90 | const segmentFiles = replayFiles.filter(f => f.startsWith(shouldStartWith) && f.endsWith('.ts')) | ||
91 | await hlsPlaylistToFragmentedMP4(replayDirectory, segmentFiles, mp4TmpPath) | ||
92 | |||
93 | if (!duration) { | ||
94 | duration = await getDurationFromVideoFile(mp4TmpPath) | ||
95 | } | ||
96 | |||
97 | resolutions.push(videoFileResolution) | ||
98 | } | ||
99 | |||
100 | await cleanupLiveFiles(hlsDirectory) | 73 | await cleanupLiveFiles(hlsDirectory) |
101 | 74 | ||
102 | await live.destroy() | 75 | await live.destroy() |
@@ -105,7 +78,6 @@ async function saveLive (video: MVideo, live: MVideoLive) { | |||
105 | // Reinit views | 78 | // Reinit views |
106 | video.views = 0 | 79 | video.views = 0 |
107 | video.state = VideoState.TO_TRANSCODE | 80 | video.state = VideoState.TO_TRANSCODE |
108 | video.duration = duration | ||
109 | 81 | ||
110 | await video.save() | 82 | await video.save() |
111 | 83 | ||
@@ -116,21 +88,35 @@ async function saveLive (video: MVideo, live: MVideoLive) { | |||
116 | await VideoFileModel.removeHLSFilesOfVideoId(hlsPlaylist.id) | 88 | await VideoFileModel.removeHLSFilesOfVideoId(hlsPlaylist.id) |
117 | hlsPlaylist.VideoFiles = [] | 89 | hlsPlaylist.VideoFiles = [] |
118 | 90 | ||
119 | for (const resolution of resolutions) { | 91 | const replayFiles = await readdir(replayDirectory) |
120 | const videoInputPath = buildMP4TmpPath(hlsDirectory, resolution) | 92 | let duration: number |
121 | const { isPortraitMode } = await getVideoFileResolution(videoInputPath) | ||
122 | 93 | ||
123 | await generateHlsPlaylist({ | 94 | for (const playlistFile of playlistFiles) { |
95 | const playlistPath = join(replayDirectory, playlistFile) | ||
96 | const { videoFileResolution, isPortraitMode } = await getVideoFileResolution(playlistPath) | ||
97 | |||
98 | // Playlist name is for example 3.m3u8 | ||
99 | // Segments names are 3-0.ts 3-1.ts etc | ||
100 | const shouldStartWith = playlistFile.replace(/\.m3u8$/, '') + '-' | ||
101 | |||
102 | const segmentFiles = replayFiles.filter(f => f.startsWith(shouldStartWith) && f.endsWith('.ts')) | ||
103 | |||
104 | const outputPath = await generateHlsPlaylistFromTS({ | ||
124 | video: videoWithFiles, | 105 | video: videoWithFiles, |
125 | videoInputPath, | 106 | replayDirectory, |
126 | resolution: resolution, | 107 | segmentFiles, |
127 | copyCodecs: true, | 108 | resolution: videoFileResolution, |
128 | isPortraitMode | 109 | isPortraitMode |
129 | }) | 110 | }) |
130 | 111 | ||
131 | await remove(videoInputPath) | 112 | if (!duration) { |
113 | videoWithFiles.duration = await getDurationFromVideoFile(outputPath) | ||
114 | await videoWithFiles.save() | ||
115 | } | ||
132 | } | 116 | } |
133 | 117 | ||
118 | await remove(replayDirectory) | ||
119 | |||
134 | // Regenerate the thumbnail & preview? | 120 | // Regenerate the thumbnail & preview? |
135 | if (videoWithFiles.getMiniature().automaticallyGenerated === true) { | 121 | if (videoWithFiles.getMiniature().automaticallyGenerated === true) { |
136 | await generateVideoMiniature(videoWithFiles, videoWithFiles.getMaxQualityFile(), ThumbnailType.MINIATURE) | 122 | await generateVideoMiniature(videoWithFiles, videoWithFiles.getMaxQualityFile(), ThumbnailType.MINIATURE) |
@@ -161,8 +147,7 @@ async function cleanupLiveFiles (hlsDirectory: string) { | |||
161 | filename.endsWith('.m3u8') || | 147 | filename.endsWith('.m3u8') || |
162 | filename.endsWith('.mpd') || | 148 | filename.endsWith('.mpd') || |
163 | filename.endsWith('.m4s') || | 149 | filename.endsWith('.m4s') || |
164 | filename.endsWith('.tmp') || | 150 | filename.endsWith('.tmp') |
165 | filename === VIDEO_LIVE.REPLAY_DIRECTORY | ||
166 | ) { | 151 | ) { |
167 | const p = join(hlsDirectory, filename) | 152 | const p = join(hlsDirectory, filename) |
168 | 153 | ||
@@ -171,7 +156,3 @@ async function cleanupLiveFiles (hlsDirectory: string) { | |||
171 | } | 156 | } |
172 | } | 157 | } |
173 | } | 158 | } |
174 | |||
175 | function buildMP4TmpPath (basePath: string, resolution: number) { | ||
176 | return join(basePath, resolution + '-tmp.mp4') | ||
177 | } | ||