mirror of https://github.com/Chocobozzz/PeerTube
Merge branch 'release/6.2.0' into develop
commit
0a87497a11
|
@ -17,11 +17,15 @@ import { buildUUID } from '@peertube/peertube-node-utils'
|
||||||
import { FSWatcher, watch } from 'chokidar'
|
import { FSWatcher, watch } from 'chokidar'
|
||||||
import { FfmpegCommand } from 'fluent-ffmpeg'
|
import { FfmpegCommand } from 'fluent-ffmpeg'
|
||||||
import { ensureDir, remove } from 'fs-extra/esm'
|
import { ensureDir, remove } from 'fs-extra/esm'
|
||||||
|
import { readFile } from 'fs/promises'
|
||||||
import { basename, join } from 'path'
|
import { basename, join } from 'path'
|
||||||
import { ConfigManager } from '../../../shared/config-manager.js'
|
import { ConfigManager } from '../../../shared/config-manager.js'
|
||||||
import { logger } from '../../../shared/index.js'
|
import { logger } from '../../../shared/index.js'
|
||||||
import { buildFFmpegLive, ProcessOptions } from './common.js'
|
import { buildFFmpegLive, ProcessOptions } from './common.js'
|
||||||
|
|
||||||
|
type CustomLiveRTMPHLSTranscodingUpdatePayload =
|
||||||
|
Omit<LiveRTMPHLSTranscodingUpdatePayload, 'resolutionPlaylistFile'> & { resolutionPlaylistFile?: [ Buffer, string ] | Blob | string }
|
||||||
|
|
||||||
export class ProcessLiveRTMPHLSTranscoding {
|
export class ProcessLiveRTMPHLSTranscoding {
|
||||||
|
|
||||||
private readonly outputPath: string
|
private readonly outputPath: string
|
||||||
|
@ -33,6 +37,8 @@ export class ProcessLiveRTMPHLSTranscoding {
|
||||||
private readonly playlistsCreated = new Set<string>()
|
private readonly playlistsCreated = new Set<string>()
|
||||||
private allPlaylistsCreated = false
|
private allPlaylistsCreated = false
|
||||||
|
|
||||||
|
private latestFilteredPlaylistContent: { [name: string]: string } = {}
|
||||||
|
|
||||||
private ffmpegCommand: FfmpegCommand
|
private ffmpegCommand: FfmpegCommand
|
||||||
|
|
||||||
private ended = false
|
private ended = false
|
||||||
|
@ -248,7 +254,7 @@ export class ProcessLiveRTMPHLSTranscoding {
|
||||||
|
|
||||||
const videoChunkFilename = basename(deletedChunk)
|
const videoChunkFilename = basename(deletedChunk)
|
||||||
|
|
||||||
let payload: LiveRTMPHLSTranscodingUpdatePayload = {
|
let payload: CustomLiveRTMPHLSTranscodingUpdatePayload = {
|
||||||
type: 'remove-chunk',
|
type: 'remove-chunk',
|
||||||
videoChunkFilename
|
videoChunkFilename
|
||||||
}
|
}
|
||||||
|
@ -258,9 +264,10 @@ export class ProcessLiveRTMPHLSTranscoding {
|
||||||
|
|
||||||
payload = {
|
payload = {
|
||||||
...payload,
|
...payload,
|
||||||
|
|
||||||
masterPlaylistFile: join(this.outputPath, 'master.m3u8'),
|
masterPlaylistFile: join(this.outputPath, 'master.m3u8'),
|
||||||
resolutionPlaylistFilename: playlistName,
|
resolutionPlaylistFilename: playlistName,
|
||||||
resolutionPlaylistFile: join(this.outputPath, playlistName)
|
resolutionPlaylistFile: this.buildPlaylistFileParam(playlistName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,7 +285,7 @@ export class ProcessLiveRTMPHLSTranscoding {
|
||||||
|
|
||||||
const videoChunkFilename = basename(chunk)
|
const videoChunkFilename = basename(chunk)
|
||||||
|
|
||||||
let payload: LiveRTMPHLSTranscodingUpdatePayload = {
|
let payload: CustomLiveRTMPHLSTranscodingUpdatePayload = {
|
||||||
type: 'add-chunk',
|
type: 'add-chunk',
|
||||||
videoChunkFilename,
|
videoChunkFilename,
|
||||||
videoChunkFile: chunk
|
videoChunkFile: chunk
|
||||||
|
@ -287,11 +294,14 @@ export class ProcessLiveRTMPHLSTranscoding {
|
||||||
if (this.allPlaylistsCreated) {
|
if (this.allPlaylistsCreated) {
|
||||||
const playlistName = this.getPlaylistName(videoChunkFilename)
|
const playlistName = this.getPlaylistName(videoChunkFilename)
|
||||||
|
|
||||||
|
await this.updatePlaylistContent(playlistName, videoChunkFilename)
|
||||||
|
|
||||||
payload = {
|
payload = {
|
||||||
...payload,
|
...payload,
|
||||||
|
|
||||||
masterPlaylistFile: join(this.outputPath, 'master.m3u8'),
|
masterPlaylistFile: join(this.outputPath, 'master.m3u8'),
|
||||||
resolutionPlaylistFilename: playlistName,
|
resolutionPlaylistFilename: playlistName,
|
||||||
resolutionPlaylistFile: join(this.outputPath, playlistName)
|
resolutionPlaylistFile: this.buildPlaylistFileParam(playlistName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,7 +314,7 @@ export class ProcessLiveRTMPHLSTranscoding {
|
||||||
await Promise.all(promises)
|
await Promise.all(promises)
|
||||||
}
|
}
|
||||||
|
|
||||||
private async updateWithRetry (payload: LiveRTMPHLSTranscodingUpdatePayload, currentTry = 1): Promise<any> {
|
private async updateWithRetry (payload: CustomLiveRTMPHLSTranscodingUpdatePayload, currentTry = 1): Promise<any> {
|
||||||
if (this.ended || this.errored) return
|
if (this.ended || this.errored) return
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -312,7 +322,7 @@ export class ProcessLiveRTMPHLSTranscoding {
|
||||||
jobToken: this.options.job.jobToken,
|
jobToken: this.options.job.jobToken,
|
||||||
jobUUID: this.options.job.uuid,
|
jobUUID: this.options.job.uuid,
|
||||||
runnerToken: this.options.runnerToken,
|
runnerToken: this.options.runnerToken,
|
||||||
payload
|
payload: payload as any
|
||||||
})
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (currentTry >= 3) throw err
|
if (currentTry >= 3) throw err
|
||||||
|
@ -335,6 +345,22 @@ export class ProcessLiveRTMPHLSTranscoding {
|
||||||
return basename(segmentPath).match(playlistIdMatcher)[1]
|
return basename(segmentPath).match(playlistIdMatcher)[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async updatePlaylistContent (playlistName: string, latestChunkFilename: string) {
|
||||||
|
const m3u8Path = join(this.outputPath, playlistName)
|
||||||
|
const playlistContent = await readFile(m3u8Path, 'utf-8')
|
||||||
|
|
||||||
|
// Remove new chunk references, that will be processed later
|
||||||
|
this.latestFilteredPlaylistContent[playlistName] = playlistContent
|
||||||
|
.substring(0, playlistContent.lastIndexOf(latestChunkFilename) + latestChunkFilename.length) + '\n'
|
||||||
|
}
|
||||||
|
|
||||||
|
private buildPlaylistFileParam (playlistName: string) {
|
||||||
|
return [
|
||||||
|
Buffer.from(this.latestFilteredPlaylistContent[playlistName], 'utf-8'),
|
||||||
|
join(this.outputPath, 'master.m3u8')
|
||||||
|
] as [ Buffer, string ]
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
private cleanup () {
|
private cleanup () {
|
||||||
|
|
|
@ -141,9 +141,20 @@ export function makeUploadRequest (options: CommonRequestParams & {
|
||||||
if (!value) return
|
if (!value) return
|
||||||
|
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
req.attach(attach, buildAbsoluteFixturePath(value[0]), value[1])
|
req.attach(
|
||||||
|
attach,
|
||||||
|
value[0] instanceof Buffer
|
||||||
|
? value[0]
|
||||||
|
: buildAbsoluteFixturePath(value[0]),
|
||||||
|
value[1]
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
req.attach(attach, buildAbsoluteFixturePath(value))
|
req.attach(
|
||||||
|
attach,
|
||||||
|
value instanceof Buffer
|
||||||
|
? value
|
||||||
|
: buildAbsoluteFixturePath(value)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue