diff options
Diffstat (limited to 'server/lib/job-queue/handlers')
4 files changed, 75 insertions, 50 deletions
diff --git a/server/lib/job-queue/handlers/manage-video-torrent.ts b/server/lib/job-queue/handlers/manage-video-torrent.ts index 03aa414c9..425915c96 100644 --- a/server/lib/job-queue/handlers/manage-video-torrent.ts +++ b/server/lib/job-queue/handlers/manage-video-torrent.ts | |||
@@ -82,7 +82,7 @@ async function loadStreamingPlaylistOrLog (streamingPlaylistId: number) { | |||
82 | async function loadFileOrLog (videoFileId: number) { | 82 | async function loadFileOrLog (videoFileId: number) { |
83 | if (!videoFileId) return undefined | 83 | if (!videoFileId) return undefined |
84 | 84 | ||
85 | const file = await VideoFileModel.loadWithVideo(videoFileId) | 85 | const file = await VideoFileModel.load(videoFileId) |
86 | 86 | ||
87 | if (!file) { | 87 | if (!file) { |
88 | logger.debug('Do not process torrent for file %d: does not exist anymore.', videoFileId) | 88 | logger.debug('Do not process torrent for file %d: does not exist anymore.', videoFileId) |
diff --git a/server/lib/job-queue/handlers/move-to-object-storage.ts b/server/lib/job-queue/handlers/move-to-object-storage.ts index 28c3d325d..0b68555d1 100644 --- a/server/lib/job-queue/handlers/move-to-object-storage.ts +++ b/server/lib/job-queue/handlers/move-to-object-storage.ts | |||
@@ -3,10 +3,10 @@ import { remove } from 'fs-extra' | |||
3 | import { join } from 'path' | 3 | import { join } from 'path' |
4 | import { logger, loggerTagsFactory } from '@server/helpers/logger' | 4 | import { logger, loggerTagsFactory } from '@server/helpers/logger' |
5 | import { updateTorrentMetadata } from '@server/helpers/webtorrent' | 5 | import { updateTorrentMetadata } from '@server/helpers/webtorrent' |
6 | import { CONFIG } from '@server/initializers/config' | ||
7 | import { P2P_MEDIA_LOADER_PEER_VERSION } from '@server/initializers/constants' | 6 | import { P2P_MEDIA_LOADER_PEER_VERSION } from '@server/initializers/constants' |
8 | import { storeHLSFileFromFilename, storeWebTorrentFile } from '@server/lib/object-storage' | 7 | import { storeHLSFileFromFilename, storeWebTorrentFile } from '@server/lib/object-storage' |
9 | import { getHLSDirectory, getHlsResolutionPlaylistFilename } from '@server/lib/paths' | 8 | import { getHLSDirectory, getHlsResolutionPlaylistFilename } from '@server/lib/paths' |
9 | import { VideoPathManager } from '@server/lib/video-path-manager' | ||
10 | import { moveToFailedMoveToObjectStorageState, moveToNextState } from '@server/lib/video-state' | 10 | import { moveToFailedMoveToObjectStorageState, moveToNextState } from '@server/lib/video-state' |
11 | import { VideoModel } from '@server/models/video/video' | 11 | import { VideoModel } from '@server/models/video/video' |
12 | import { VideoJobInfoModel } from '@server/models/video/video-job-info' | 12 | import { VideoJobInfoModel } from '@server/models/video/video-job-info' |
@@ -72,9 +72,9 @@ async function moveWebTorrentFiles (video: MVideoWithAllFiles) { | |||
72 | for (const file of video.VideoFiles) { | 72 | for (const file of video.VideoFiles) { |
73 | if (file.storage !== VideoStorage.FILE_SYSTEM) continue | 73 | if (file.storage !== VideoStorage.FILE_SYSTEM) continue |
74 | 74 | ||
75 | const fileUrl = await storeWebTorrentFile(file.filename) | 75 | const fileUrl = await storeWebTorrentFile(video, file) |
76 | 76 | ||
77 | const oldPath = join(CONFIG.STORAGE.VIDEOS_DIR, file.filename) | 77 | const oldPath = VideoPathManager.Instance.getFSVideoFileOutputPath(video, file) |
78 | await onFileMoved({ videoOrPlaylist: video, file, fileUrl, oldPath }) | 78 | await onFileMoved({ videoOrPlaylist: video, file, fileUrl, oldPath }) |
79 | } | 79 | } |
80 | } | 80 | } |
diff --git a/server/lib/job-queue/handlers/video-live-ending.ts b/server/lib/job-queue/handlers/video-live-ending.ts index 7dbffc955..c6263f55a 100644 --- a/server/lib/job-queue/handlers/video-live-ending.ts +++ b/server/lib/job-queue/handlers/video-live-ending.ts | |||
@@ -18,6 +18,7 @@ import { VideoStreamingPlaylistModel } from '@server/models/video/video-streamin | |||
18 | import { MVideo, MVideoLive, MVideoLiveSession, MVideoWithAllFiles } from '@server/types/models' | 18 | import { MVideo, MVideoLive, MVideoLiveSession, MVideoWithAllFiles } from '@server/types/models' |
19 | import { ThumbnailType, VideoLiveEndingPayload, VideoState } from '@shared/models' | 19 | import { ThumbnailType, VideoLiveEndingPayload, VideoState } from '@shared/models' |
20 | import { logger, loggerTagsFactory } from '../../../helpers/logger' | 20 | import { logger, loggerTagsFactory } from '../../../helpers/logger' |
21 | import { VideoPathManager } from '@server/lib/video-path-manager' | ||
21 | 22 | ||
22 | const lTags = loggerTagsFactory('live', 'job') | 23 | const lTags = loggerTagsFactory('live', 'job') |
23 | 24 | ||
@@ -205,18 +206,27 @@ async function assignReplayFilesToVideo (options: { | |||
205 | const concatenatedTsFiles = await readdir(replayDirectory) | 206 | const concatenatedTsFiles = await readdir(replayDirectory) |
206 | 207 | ||
207 | for (const concatenatedTsFile of concatenatedTsFiles) { | 208 | for (const concatenatedTsFile of concatenatedTsFiles) { |
209 | const inputFileMutexReleaser = await VideoPathManager.Instance.lockFiles(video.uuid) | ||
210 | |||
208 | const concatenatedTsFilePath = join(replayDirectory, concatenatedTsFile) | 211 | const concatenatedTsFilePath = join(replayDirectory, concatenatedTsFile) |
209 | 212 | ||
210 | const probe = await ffprobePromise(concatenatedTsFilePath) | 213 | const probe = await ffprobePromise(concatenatedTsFilePath) |
211 | const { audioStream } = await getAudioStream(concatenatedTsFilePath, probe) | 214 | const { audioStream } = await getAudioStream(concatenatedTsFilePath, probe) |
212 | const { resolution } = await getVideoStreamDimensionsInfo(concatenatedTsFilePath, probe) | 215 | const { resolution } = await getVideoStreamDimensionsInfo(concatenatedTsFilePath, probe) |
213 | 216 | ||
214 | await generateHlsPlaylistResolutionFromTS({ | 217 | try { |
215 | video, | 218 | await generateHlsPlaylistResolutionFromTS({ |
216 | concatenatedTsFilePath, | 219 | video, |
217 | resolution, | 220 | inputFileMutexReleaser, |
218 | isAAC: audioStream?.codec_name === 'aac' | 221 | concatenatedTsFilePath, |
219 | }) | 222 | resolution, |
223 | isAAC: audioStream?.codec_name === 'aac' | ||
224 | }) | ||
225 | } catch (err) { | ||
226 | logger.error('Cannot generate HLS playlist resolution from TS files.', { err }) | ||
227 | } | ||
228 | |||
229 | inputFileMutexReleaser() | ||
220 | } | 230 | } |
221 | 231 | ||
222 | return video | 232 | return video |
diff --git a/server/lib/job-queue/handlers/video-transcoding.ts b/server/lib/job-queue/handlers/video-transcoding.ts index b0e92acf7..48c675678 100644 --- a/server/lib/job-queue/handlers/video-transcoding.ts +++ b/server/lib/job-queue/handlers/video-transcoding.ts | |||
@@ -94,15 +94,24 @@ async function handleHLSJob (job: Job, payload: HLSTranscodingPayload, video: MV | |||
94 | 94 | ||
95 | const videoOrStreamingPlaylist = videoFileInput.getVideoOrStreamingPlaylist() | 95 | const videoOrStreamingPlaylist = videoFileInput.getVideoOrStreamingPlaylist() |
96 | 96 | ||
97 | await VideoPathManager.Instance.makeAvailableVideoFile(videoFileInput.withVideoOrPlaylist(videoOrStreamingPlaylist), videoInputPath => { | 97 | const inputFileMutexReleaser = await VideoPathManager.Instance.lockFiles(video.uuid) |
98 | return generateHlsPlaylistResolution({ | 98 | |
99 | video, | 99 | try { |
100 | videoInputPath, | 100 | await videoFileInput.getVideo().reload() |
101 | resolution: payload.resolution, | 101 | |
102 | copyCodecs: payload.copyCodecs, | 102 | await VideoPathManager.Instance.makeAvailableVideoFile(videoFileInput.withVideoOrPlaylist(videoOrStreamingPlaylist), videoInputPath => { |
103 | job | 103 | return generateHlsPlaylistResolution({ |
104 | video, | ||
105 | videoInputPath, | ||
106 | inputFileMutexReleaser, | ||
107 | resolution: payload.resolution, | ||
108 | copyCodecs: payload.copyCodecs, | ||
109 | job | ||
110 | }) | ||
104 | }) | 111 | }) |
105 | }) | 112 | } finally { |
113 | inputFileMutexReleaser() | ||
114 | } | ||
106 | 115 | ||
107 | logger.info('HLS transcoding job for %s ended.', video.uuid, lTags(video.uuid)) | 116 | logger.info('HLS transcoding job for %s ended.', video.uuid, lTags(video.uuid)) |
108 | 117 | ||
@@ -177,38 +186,44 @@ async function onVideoFirstWebTorrentTranscoding ( | |||
177 | transcodeType: TranscodeVODOptionsType, | 186 | transcodeType: TranscodeVODOptionsType, |
178 | user: MUserId | 187 | user: MUserId |
179 | ) { | 188 | ) { |
180 | const { resolution, audioStream } = await videoArg.probeMaxQualityFile() | 189 | const mutexReleaser = await VideoPathManager.Instance.lockFiles(videoArg.uuid) |
181 | 190 | ||
182 | // Maybe the video changed in database, refresh it | 191 | try { |
183 | const videoDatabase = await VideoModel.loadFull(videoArg.uuid) | 192 | // Maybe the video changed in database, refresh it |
184 | // Video does not exist anymore | 193 | const videoDatabase = await VideoModel.loadFull(videoArg.uuid) |
185 | if (!videoDatabase) return undefined | 194 | // Video does not exist anymore |
186 | 195 | if (!videoDatabase) return undefined | |
187 | // Generate HLS version of the original file | 196 | |
188 | const originalFileHLSPayload = { | 197 | const { resolution, audioStream } = await videoDatabase.probeMaxQualityFile() |
189 | ...payload, | 198 | |
190 | 199 | // Generate HLS version of the original file | |
191 | hasAudio: !!audioStream, | 200 | const originalFileHLSPayload = { |
192 | resolution: videoDatabase.getMaxQualityFile().resolution, | 201 | ...payload, |
193 | // If we quick transcoded original file, force transcoding for HLS to avoid some weird playback issues | 202 | |
194 | copyCodecs: transcodeType !== 'quick-transcode', | 203 | hasAudio: !!audioStream, |
195 | isMaxQuality: true | 204 | resolution: videoDatabase.getMaxQualityFile().resolution, |
196 | } | 205 | // If we quick transcoded original file, force transcoding for HLS to avoid some weird playback issues |
197 | const hasHls = await createHlsJobIfEnabled(user, originalFileHLSPayload) | 206 | copyCodecs: transcodeType !== 'quick-transcode', |
198 | const hasNewResolutions = await createLowerResolutionsJobs({ | 207 | isMaxQuality: true |
199 | video: videoDatabase, | 208 | } |
200 | user, | 209 | const hasHls = await createHlsJobIfEnabled(user, originalFileHLSPayload) |
201 | videoFileResolution: resolution, | 210 | const hasNewResolutions = await createLowerResolutionsJobs({ |
202 | hasAudio: !!audioStream, | 211 | video: videoDatabase, |
203 | type: 'webtorrent', | 212 | user, |
204 | isNewVideo: payload.isNewVideo ?? true | 213 | videoFileResolution: resolution, |
205 | }) | 214 | hasAudio: !!audioStream, |
206 | 215 | type: 'webtorrent', | |
207 | await VideoJobInfoModel.decrease(videoDatabase.uuid, 'pendingTranscode') | 216 | isNewVideo: payload.isNewVideo ?? true |
208 | 217 | }) | |
209 | // Move to next state if there are no other resolutions to generate | 218 | |
210 | if (!hasHls && !hasNewResolutions) { | 219 | await VideoJobInfoModel.decrease(videoDatabase.uuid, 'pendingTranscode') |
211 | await retryTransactionWrapper(moveToNextState, { video: videoDatabase, isNewVideo: payload.isNewVideo }) | 220 | |
221 | // Move to next state if there are no other resolutions to generate | ||
222 | if (!hasHls && !hasNewResolutions) { | ||
223 | await retryTransactionWrapper(moveToNextState, { video: videoDatabase, isNewVideo: payload.isNewVideo }) | ||
224 | } | ||
225 | } finally { | ||
226 | mutexReleaser() | ||
212 | } | 227 | } |
213 | } | 228 | } |
214 | 229 | ||