-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'
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')
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()
}) {
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
}) {
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
if (streamingPlaylist) {
if (permanentLive) {
- await cleanupPermanentLive(video, streamingPlaylist)
+ await cleanupAndDestroyPermanentLive(video, streamingPlaylist)
} else {
await cleanupUnsavedNormalLive(video, streamingPlaylist)
}