aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/lib/job-queue
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2022-05-03 11:38:07 +0200
committerChocobozzz <me@florianbigard.com>2022-05-03 14:49:15 +0200
commit26e3e98ff0e222a9fb9226938ac6902af77921bd (patch)
tree73d1c6f2524e380862d3365f12043fc319d40841 /server/lib/job-queue
parent86c5229b4d726202378ef46854383bcafca22310 (diff)
downloadPeerTube-26e3e98ff0e222a9fb9226938ac6902af77921bd.tar.gz
PeerTube-26e3e98ff0e222a9fb9226938ac6902af77921bd.tar.zst
PeerTube-26e3e98ff0e222a9fb9226938ac6902af77921bd.zip
Support live session in server
Diffstat (limited to 'server/lib/job-queue')
-rw-r--r--server/lib/job-queue/handlers/video-live-ending.ts87
1 files changed, 60 insertions, 27 deletions
diff --git a/server/lib/job-queue/handlers/video-live-ending.ts b/server/lib/job-queue/handlers/video-live-ending.ts
index 1e290338c..55fd09344 100644
--- a/server/lib/job-queue/handlers/video-live-ending.ts
+++ b/server/lib/job-queue/handlers/video-live-ending.ts
@@ -15,13 +15,14 @@ import { generateVideoMiniature } from '@server/lib/thumbnail'
15import { generateHlsPlaylistResolutionFromTS } from '@server/lib/transcoding/transcoding' 15import { generateHlsPlaylistResolutionFromTS } from '@server/lib/transcoding/transcoding'
16import { moveToNextState } from '@server/lib/video-state' 16import { moveToNextState } from '@server/lib/video-state'
17import { VideoModel } from '@server/models/video/video' 17import { VideoModel } from '@server/models/video/video'
18import { VideoBlacklistModel } from '@server/models/video/video-blacklist'
18import { VideoFileModel } from '@server/models/video/video-file' 19import { VideoFileModel } from '@server/models/video/video-file'
19import { VideoLiveModel } from '@server/models/video/video-live' 20import { VideoLiveModel } from '@server/models/video/video-live'
21import { VideoLiveSessionModel } from '@server/models/video/video-live-session'
20import { VideoStreamingPlaylistModel } from '@server/models/video/video-streaming-playlist' 22import { VideoStreamingPlaylistModel } from '@server/models/video/video-streaming-playlist'
21import { MVideo, MVideoLive, MVideoWithAllFiles } from '@server/types/models' 23import { MVideo, MVideoLive, MVideoLiveSession, MVideoWithAllFiles } from '@server/types/models'
22import { ThumbnailType, VideoLiveEndingPayload, VideoState } from '@shared/models' 24import { ThumbnailType, VideoLiveEndingPayload, VideoState } from '@shared/models'
23import { logger } from '../../../helpers/logger' 25import { logger } from '../../../helpers/logger'
24import { VideoBlacklistModel } from '@server/models/video/video-blacklist'
25 26
26async function processVideoLiveEnding (job: Job) { 27async function processVideoLiveEnding (job: Job) {
27 const payload = job.data as VideoLiveEndingPayload 28 const payload = job.data as VideoLiveEndingPayload
@@ -32,27 +33,28 @@ async function processVideoLiveEnding (job: Job) {
32 logger.warn('Video live %d does not exist anymore. Cannot process live ending.', payload.videoId) 33 logger.warn('Video live %d does not exist anymore. Cannot process live ending.', payload.videoId)
33 } 34 }
34 35
35 const video = await VideoModel.load(payload.videoId) 36 const liveVideo = await VideoModel.load(payload.videoId)
36 const live = await VideoLiveModel.loadByVideoId(payload.videoId) 37 const live = await VideoLiveModel.loadByVideoId(payload.videoId)
38 const liveSession = await VideoLiveSessionModel.load(payload.liveSessionId)
37 39
38 if (!video || !live) { 40 if (!liveVideo || !live || !liveSession) {
39 logError() 41 logError()
40 return 42 return
41 } 43 }
42 44
43 LiveSegmentShaStore.Instance.cleanupShaSegments(video.uuid) 45 LiveSegmentShaStore.Instance.cleanupShaSegments(liveVideo.uuid)
44 46
45 if (live.saveReplay !== true) { 47 if (live.saveReplay !== true) {
46 return cleanupLiveAndFederate(video) 48 return cleanupLiveAndFederate({ liveVideo })
47 } 49 }
48 50
49 if (live.permanentLive) { 51 if (live.permanentLive) {
50 await saveReplayToExternalVideo(video, payload.publishedAt, payload.replayDirectory) 52 await saveReplayToExternalVideo({ liveVideo, liveSession, publishedAt: payload.publishedAt, replayDirectory: payload.replayDirectory })
51 53
52 return cleanupLiveAndFederate(video) 54 return cleanupLiveAndFederate({ liveVideo })
53 } 55 }
54 56
55 return replaceLiveByReplay(video, live, payload.replayDirectory) 57 return replaceLiveByReplay({ liveVideo, live, liveSession, replayDirectory: payload.replayDirectory })
56} 58}
57 59
58// --------------------------------------------------------------------------- 60// ---------------------------------------------------------------------------
@@ -63,7 +65,14 @@ export {
63 65
64// --------------------------------------------------------------------------- 66// ---------------------------------------------------------------------------
65 67
66async function saveReplayToExternalVideo (liveVideo: MVideo, publishedAt: string, replayDirectory: string) { 68async function saveReplayToExternalVideo (options: {
69 liveVideo: MVideo
70 liveSession: MVideoLiveSession
71 publishedAt: string
72 replayDirectory: string
73}) {
74 const { liveVideo, liveSession, publishedAt, replayDirectory } = options
75
67 await cleanupTMPLiveFiles(getLiveDirectory(liveVideo)) 76 await cleanupTMPLiveFiles(getLiveDirectory(liveVideo))
68 77
69 const video = new VideoModel({ 78 const video = new VideoModel({
@@ -78,7 +87,7 @@ async function saveReplayToExternalVideo (liveVideo: MVideo, publishedAt: string
78 language: liveVideo.language, 87 language: liveVideo.language,
79 commentsEnabled: liveVideo.commentsEnabled, 88 commentsEnabled: liveVideo.commentsEnabled,
80 downloadEnabled: liveVideo.downloadEnabled, 89 downloadEnabled: liveVideo.downloadEnabled,
81 waitTranscoding: liveVideo.waitTranscoding, 90 waitTranscoding: true,
82 nsfw: liveVideo.nsfw, 91 nsfw: liveVideo.nsfw,
83 description: liveVideo.description, 92 description: liveVideo.description,
84 support: liveVideo.support, 93 support: liveVideo.support,
@@ -94,6 +103,9 @@ async function saveReplayToExternalVideo (liveVideo: MVideo, publishedAt: string
94 103
95 await video.save() 104 await video.save()
96 105
106 liveSession.replayVideoId = video.id
107 await liveSession.save()
108
97 // If live is blacklisted, also blacklist the replay 109 // If live is blacklisted, also blacklist the replay
98 const blacklist = await VideoBlacklistModel.loadByVideoId(liveVideo.id) 110 const blacklist = await VideoBlacklistModel.loadByVideoId(liveVideo.id)
99 if (blacklist) { 111 if (blacklist) {
@@ -105,7 +117,7 @@ async function saveReplayToExternalVideo (liveVideo: MVideo, publishedAt: string
105 }) 117 })
106 } 118 }
107 119
108 await assignReplaysToVideo(video, replayDirectory) 120 await assignReplayFilesToVideo({ video, replayDirectory })
109 121
110 await remove(replayDirectory) 122 await remove(replayDirectory)
111 123
@@ -117,18 +129,29 @@ async function saveReplayToExternalVideo (liveVideo: MVideo, publishedAt: string
117 await moveToNextState({ video, isNewVideo: true }) 129 await moveToNextState({ video, isNewVideo: true })
118} 130}
119 131
120async function replaceLiveByReplay (video: MVideo, live: MVideoLive, replayDirectory: string) { 132async function replaceLiveByReplay (options: {
121 await cleanupTMPLiveFiles(getLiveDirectory(video)) 133 liveVideo: MVideo
134 liveSession: MVideoLiveSession
135 live: MVideoLive
136 replayDirectory: string
137}) {
138 const { liveVideo, liveSession, live, replayDirectory } = options
139
140 await cleanupTMPLiveFiles(getLiveDirectory(liveVideo))
122 141
123 await live.destroy() 142 await live.destroy()
124 143
125 video.isLive = false 144 liveVideo.isLive = false
126 video.state = VideoState.TO_TRANSCODE 145 liveVideo.waitTranscoding = true
146 liveVideo.state = VideoState.TO_TRANSCODE
127 147
128 await video.save() 148 await liveVideo.save()
149
150 liveSession.replayVideoId = liveVideo.id
151 await liveSession.save()
129 152
130 // Remove old HLS playlist video files 153 // Remove old HLS playlist video files
131 const videoWithFiles = await VideoModel.loadAndPopulateAccountAndServerAndTags(video.id) 154 const videoWithFiles = await VideoModel.loadAndPopulateAccountAndServerAndTags(liveVideo.id)
132 155
133 const hlsPlaylist = videoWithFiles.getHLSPlaylist() 156 const hlsPlaylist = videoWithFiles.getHLSPlaylist()
134 await VideoFileModel.removeHLSFilesOfVideoId(hlsPlaylist.id) 157 await VideoFileModel.removeHLSFilesOfVideoId(hlsPlaylist.id)
@@ -139,7 +162,7 @@ async function replaceLiveByReplay (video: MVideo, live: MVideoLive, replayDirec
139 hlsPlaylist.segmentsSha256Filename = generateHlsSha256SegmentsFilename() 162 hlsPlaylist.segmentsSha256Filename = generateHlsSha256SegmentsFilename()
140 await hlsPlaylist.save() 163 await hlsPlaylist.save()
141 164
142 await assignReplaysToVideo(videoWithFiles, replayDirectory) 165 await assignReplayFilesToVideo({ video: videoWithFiles, replayDirectory })
143 166
144 await remove(getLiveReplayBaseDirectory(videoWithFiles)) 167 await remove(getLiveReplayBaseDirectory(videoWithFiles))
145 168
@@ -150,7 +173,7 @@ async function replaceLiveByReplay (video: MVideo, live: MVideoLive, replayDirec
150 videoFile: videoWithFiles.getMaxQualityFile(), 173 videoFile: videoWithFiles.getMaxQualityFile(),
151 type: ThumbnailType.MINIATURE 174 type: ThumbnailType.MINIATURE
152 }) 175 })
153 await video.addAndSaveThumbnail(miniature) 176 await videoWithFiles.addAndSaveThumbnail(miniature)
154 } 177 }
155 178
156 if (videoWithFiles.getPreview().automaticallyGenerated === true) { 179 if (videoWithFiles.getPreview().automaticallyGenerated === true) {
@@ -159,13 +182,19 @@ async function replaceLiveByReplay (video: MVideo, live: MVideoLive, replayDirec
159 videoFile: videoWithFiles.getMaxQualityFile(), 182 videoFile: videoWithFiles.getMaxQualityFile(),
160 type: ThumbnailType.PREVIEW 183 type: ThumbnailType.PREVIEW
161 }) 184 })
162 await video.addAndSaveThumbnail(preview) 185 await videoWithFiles.addAndSaveThumbnail(preview)
163 } 186 }
164 187
165 await moveToNextState({ video: videoWithFiles, isNewVideo: false }) 188 // We consider this is a new video
189 await moveToNextState({ video: videoWithFiles, isNewVideo: true })
166} 190}
167 191
168async function assignReplaysToVideo (video: MVideo, replayDirectory: string) { 192async function assignReplayFilesToVideo (options: {
193 video: MVideo
194 replayDirectory: string
195}) {
196 const { video, replayDirectory } = options
197
169 let durationDone = false 198 let durationDone = false
170 199
171 const concatenatedTsFiles = await readdir(replayDirectory) 200 const concatenatedTsFiles = await readdir(replayDirectory)
@@ -197,11 +226,15 @@ async function assignReplaysToVideo (video: MVideo, replayDirectory: string) {
197 return video 226 return video
198} 227}
199 228
200async function cleanupLiveAndFederate (video: MVideo) { 229async function cleanupLiveAndFederate (options: {
201 const streamingPlaylist = await VideoStreamingPlaylistModel.loadHLSPlaylistByVideo(video.id) 230 liveVideo: MVideo
202 await cleanupLive(video, streamingPlaylist) 231}) {
232 const { liveVideo } = options
233
234 const streamingPlaylist = await VideoStreamingPlaylistModel.loadHLSPlaylistByVideo(liveVideo.id)
235 await cleanupLive(liveVideo, streamingPlaylist)
203 236
204 const fullVideo = await VideoModel.loadAndPopulateAccountAndServerAndTags(video.id) 237 const fullVideo = await VideoModel.loadAndPopulateAccountAndServerAndTags(liveVideo.id)
205 return federateVideoIfNeeded(fullVideo, false, undefined) 238 return federateVideoIfNeeded(fullVideo, false, undefined)
206} 239}
207 240