]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blobdiff - server/lib/job-queue/handlers/video-live-ending.ts
Lock files to generate torrents/move files
[github/Chocobozzz/PeerTube.git] / server / lib / job-queue / handlers / video-live-ending.ts
index 78d0b21923ea1e2541f8bd1913ba9f2c5aca2764..c6263f55ac3df3093c3e38054b49a442d2f46bfb 100644 (file)
@@ -1,10 +1,10 @@
-import { Job } from 'bull'
+import { Job } from 'bullmq'
 import { readdir, remove } from 'fs-extra'
 import { join } from 'path'
-import { ffprobePromise, getAudioStream, getVideoStreamDimensionsInfo, getVideoStreamDuration } from '@server/helpers/ffmpeg'
+import { ffprobePromise, getAudioStream, getVideoStreamDimensionsInfo } from '@server/helpers/ffmpeg'
 import { getLocalVideoActivityPubUrl } from '@server/lib/activitypub/url'
 import { federateVideoIfNeeded } from '@server/lib/activitypub/videos'
-import { cleanupPermanentLive, cleanupTMPLiveFiles, cleanupUnsavedNormalLive } from '@server/lib/live'
+import { cleanupAndDestroyPermanentLive, cleanupTMPLiveFiles, cleanupUnsavedNormalLive } from '@server/lib/live'
 import { generateHLSMasterPlaylistFilename, generateHlsSha256SegmentsFilename, getLiveReplayBaseDirectory } from '@server/lib/paths'
 import { generateVideoMiniature } from '@server/lib/thumbnail'
 import { generateHlsPlaylistResolutionFromTS } from '@server/lib/transcoding/transcoding'
@@ -18,6 +18,7 @@ import { VideoStreamingPlaylistModel } from '@server/models/video/video-streamin
 import { MVideo, MVideoLive, MVideoLiveSession, MVideoWithAllFiles } from '@server/types/models'
 import { ThumbnailType, VideoLiveEndingPayload, VideoState } from '@shared/models'
 import { logger, loggerTagsFactory } from '../../../helpers/logger'
+import { VideoPathManager } from '@server/lib/video-path-manager'
 
 const lTags = loggerTagsFactory('live', 'job')
 
@@ -34,13 +35,13 @@ async function processVideoLiveEnding (job: Job) {
   const live = await VideoLiveModel.loadByVideoId(payload.videoId)
   const liveSession = await VideoLiveSessionModel.load(payload.liveSessionId)
 
-  const permanentLive = live.permanentLive
-
   if (!video || !live || !liveSession) {
     logError()
     return
   }
 
+  const permanentLive = live.permanentLive
+
   liveSession.endingProcessed = true
   await liveSession.save()
 
@@ -141,23 +142,22 @@ async function replaceLiveByReplay (options: {
 }) {
   const { video, liveSession, live, permanentLive, replayDirectory } = options
 
-  await cleanupTMPLiveFiles(video)
+  const videoWithFiles = await VideoModel.loadFull(video.id)
+  const hlsPlaylist = videoWithFiles.getHLSPlaylist()
+
+  await cleanupTMPLiveFiles(videoWithFiles, hlsPlaylist)
 
   await live.destroy()
 
-  video.isLive = false
-  video.waitTranscoding = true
-  video.state = VideoState.TO_TRANSCODE
+  videoWithFiles.isLive = false
+  videoWithFiles.waitTranscoding = true
+  videoWithFiles.state = VideoState.TO_TRANSCODE
 
-  await video.save()
+  await videoWithFiles.save()
 
-  liveSession.replayVideoId = video.id
+  liveSession.replayVideoId = videoWithFiles.id
   await liveSession.save()
 
-  // Remove old HLS playlist video files
-  const videoWithFiles = await VideoModel.loadFull(video.id)
-
-  const hlsPlaylist = videoWithFiles.getHLSPlaylist()
   await VideoFileModel.removeHLSFilesOfVideoId(hlsPlaylist.id)
 
   // Reset playlist
@@ -203,31 +203,30 @@ async function assignReplayFilesToVideo (options: {
 }) {
   const { video, replayDirectory } = options
 
-  let durationDone = false
-
   const concatenatedTsFiles = await readdir(replayDirectory)
 
   for (const concatenatedTsFile of concatenatedTsFiles) {
+    const inputFileMutexReleaser = await VideoPathManager.Instance.lockFiles(video.uuid)
+
     const concatenatedTsFilePath = join(replayDirectory, concatenatedTsFile)
 
     const probe = await ffprobePromise(concatenatedTsFilePath)
     const { audioStream } = await getAudioStream(concatenatedTsFilePath, probe)
-
     const { resolution } = await getVideoStreamDimensionsInfo(concatenatedTsFilePath, probe)
 
-    const { resolutionPlaylistPath: outputPath } = await generateHlsPlaylistResolutionFromTS({
-      video,
-      concatenatedTsFilePath,
-      resolution,
-      isAAC: audioStream?.codec_name === 'aac'
-    })
-
-    if (!durationDone) {
-      video.duration = await getVideoStreamDuration(outputPath)
-      await video.save()
-
-      durationDone = true
+    try {
+      await generateHlsPlaylistResolutionFromTS({
+        video,
+        inputFileMutexReleaser,
+        concatenatedTsFilePath,
+        resolution,
+        isAAC: audioStream?.codec_name === 'aac'
+      })
+    } catch (err) {
+      logger.error('Cannot generate HLS playlist resolution from TS files.', { err })
     }
+
+    inputFileMutexReleaser()
   }
 
   return video
@@ -244,7 +243,7 @@ async function cleanupLiveAndFederate (options: {
 
   if (streamingPlaylist) {
     if (permanentLive) {
-      await cleanupPermanentLive(video, streamingPlaylist)
+      await cleanupAndDestroyPermanentLive(video, streamingPlaylist)
     } else {
       await cleanupUnsavedNormalLive(video, streamingPlaylist)
     }