diff options
author | Chocobozzz <me@florianbigard.com> | 2022-05-03 11:38:07 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2022-05-03 14:49:15 +0200 |
commit | 26e3e98ff0e222a9fb9226938ac6902af77921bd (patch) | |
tree | 73d1c6f2524e380862d3365f12043fc319d40841 /server/lib/job-queue | |
parent | 86c5229b4d726202378ef46854383bcafca22310 (diff) | |
download | PeerTube-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.ts | 87 |
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' | |||
15 | import { generateHlsPlaylistResolutionFromTS } from '@server/lib/transcoding/transcoding' | 15 | import { generateHlsPlaylistResolutionFromTS } from '@server/lib/transcoding/transcoding' |
16 | import { moveToNextState } from '@server/lib/video-state' | 16 | import { moveToNextState } from '@server/lib/video-state' |
17 | import { VideoModel } from '@server/models/video/video' | 17 | import { VideoModel } from '@server/models/video/video' |
18 | import { VideoBlacklistModel } from '@server/models/video/video-blacklist' | ||
18 | import { VideoFileModel } from '@server/models/video/video-file' | 19 | import { VideoFileModel } from '@server/models/video/video-file' |
19 | import { VideoLiveModel } from '@server/models/video/video-live' | 20 | import { VideoLiveModel } from '@server/models/video/video-live' |
21 | import { VideoLiveSessionModel } from '@server/models/video/video-live-session' | ||
20 | import { VideoStreamingPlaylistModel } from '@server/models/video/video-streaming-playlist' | 22 | import { VideoStreamingPlaylistModel } from '@server/models/video/video-streaming-playlist' |
21 | import { MVideo, MVideoLive, MVideoWithAllFiles } from '@server/types/models' | 23 | import { MVideo, MVideoLive, MVideoLiveSession, MVideoWithAllFiles } from '@server/types/models' |
22 | import { ThumbnailType, VideoLiveEndingPayload, VideoState } from '@shared/models' | 24 | import { ThumbnailType, VideoLiveEndingPayload, VideoState } from '@shared/models' |
23 | import { logger } from '../../../helpers/logger' | 25 | import { logger } from '../../../helpers/logger' |
24 | import { VideoBlacklistModel } from '@server/models/video/video-blacklist' | ||
25 | 26 | ||
26 | async function processVideoLiveEnding (job: Job) { | 27 | async 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 | ||
66 | async function saveReplayToExternalVideo (liveVideo: MVideo, publishedAt: string, replayDirectory: string) { | 68 | async 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 | ||
120 | async function replaceLiveByReplay (video: MVideo, live: MVideoLive, replayDirectory: string) { | 132 | async 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 | ||
168 | async function assignReplaysToVideo (video: MVideo, replayDirectory: string) { | 192 | async 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 | ||
200 | async function cleanupLiveAndFederate (video: MVideo) { | 229 | async 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 | ||