aboutsummaryrefslogtreecommitdiffhomepage
path: root/packages/server-commands/src/videos/live.ts
diff options
context:
space:
mode:
Diffstat (limited to 'packages/server-commands/src/videos/live.ts')
-rw-r--r--packages/server-commands/src/videos/live.ts129
1 files changed, 129 insertions, 0 deletions
diff --git a/packages/server-commands/src/videos/live.ts b/packages/server-commands/src/videos/live.ts
new file mode 100644
index 000000000..05bfa1113
--- /dev/null
+++ b/packages/server-commands/src/videos/live.ts
@@ -0,0 +1,129 @@
1import { wait } from '@peertube/peertube-core-utils'
2import { VideoDetails, VideoInclude, VideoPrivacy } from '@peertube/peertube-models'
3import { buildAbsoluteFixturePath } from '@peertube/peertube-node-utils'
4import ffmpeg, { FfmpegCommand } from 'fluent-ffmpeg'
5import truncate from 'lodash-es/truncate.js'
6import { PeerTubeServer } from '../server/server.js'
7
8function sendRTMPStream (options: {
9 rtmpBaseUrl: string
10 streamKey: string
11 fixtureName?: string // default video_short.mp4
12 copyCodecs?: boolean // default false
13}) {
14 const { rtmpBaseUrl, streamKey, fixtureName = 'video_short.mp4', copyCodecs = false } = options
15
16 const fixture = buildAbsoluteFixturePath(fixtureName)
17
18 const command = ffmpeg(fixture)
19 command.inputOption('-stream_loop -1')
20 command.inputOption('-re')
21
22 if (copyCodecs) {
23 command.outputOption('-c copy')
24 } else {
25 command.outputOption('-c:v libx264')
26 command.outputOption('-g 120')
27 command.outputOption('-x264-params "no-scenecut=1"')
28 command.outputOption('-r 60')
29 }
30
31 command.outputOption('-f flv')
32
33 const rtmpUrl = rtmpBaseUrl + '/' + streamKey
34 command.output(rtmpUrl)
35
36 command.on('error', err => {
37 if (err?.message?.includes('Exiting normally')) return
38
39 if (process.env.DEBUG) console.error(err)
40 })
41
42 if (process.env.DEBUG) {
43 command.on('stderr', data => console.log(data))
44 command.on('stdout', data => console.log(data))
45 }
46
47 command.run()
48
49 return command
50}
51
52function waitFfmpegUntilError (command: FfmpegCommand, successAfterMS = 10000) {
53 return new Promise<void>((res, rej) => {
54 command.on('error', err => {
55 return rej(err)
56 })
57
58 setTimeout(() => {
59 res()
60 }, successAfterMS)
61 })
62}
63
64async function testFfmpegStreamError (command: FfmpegCommand, shouldHaveError: boolean) {
65 let error: Error
66
67 try {
68 await waitFfmpegUntilError(command, 45000)
69 } catch (err) {
70 error = err
71 }
72
73 await stopFfmpeg(command)
74
75 if (shouldHaveError && !error) throw new Error('Ffmpeg did not have an error')
76 if (!shouldHaveError && error) throw error
77}
78
79async function stopFfmpeg (command: FfmpegCommand) {
80 command.kill('SIGINT')
81
82 await wait(500)
83}
84
85async function waitUntilLivePublishedOnAllServers (servers: PeerTubeServer[], videoId: string) {
86 for (const server of servers) {
87 await server.live.waitUntilPublished({ videoId })
88 }
89}
90
91async function waitUntilLiveWaitingOnAllServers (servers: PeerTubeServer[], videoId: string) {
92 for (const server of servers) {
93 await server.live.waitUntilWaiting({ videoId })
94 }
95}
96
97async function waitUntilLiveReplacedByReplayOnAllServers (servers: PeerTubeServer[], videoId: string) {
98 for (const server of servers) {
99 await server.live.waitUntilReplacedByReplay({ videoId })
100 }
101}
102
103async function findExternalSavedVideo (server: PeerTubeServer, liveDetails: VideoDetails) {
104 const include = VideoInclude.BLACKLISTED
105 const privacyOneOf = [ VideoPrivacy.INTERNAL, VideoPrivacy.PRIVATE, VideoPrivacy.PUBLIC, VideoPrivacy.UNLISTED ]
106
107 const { data } = await server.videos.list({ token: server.accessToken, sort: '-publishedAt', include, privacyOneOf })
108
109 const videoNameSuffix = ` - ${new Date(liveDetails.publishedAt).toLocaleString()}`
110 const truncatedVideoName = truncate(liveDetails.name, {
111 length: 120 - videoNameSuffix.length
112 })
113 const toFind = truncatedVideoName + videoNameSuffix
114
115 return data.find(v => v.name === toFind)
116}
117
118export {
119 sendRTMPStream,
120 waitFfmpegUntilError,
121 testFfmpegStreamError,
122 stopFfmpeg,
123
124 waitUntilLivePublishedOnAllServers,
125 waitUntilLiveReplacedByReplayOnAllServers,
126 waitUntilLiveWaitingOnAllServers,
127
128 findExternalSavedVideo
129}